WME FC Layer

Adds a Functional Class layer for states that publish ArcGIS FC data.

目前为 2019-02-07 提交的版本,查看 最新版本

  1. /* global W */
  2. /* global Promise */
  3. /* global OL */
  4. /* global I18n */
  5. /* global unsafeWindow */
  6. /* global GM_info */
  7. /* global WazeWrap */
  8.  
  9. // // ==UserScript==
  10. // @name WME FC Layer
  11. // @namespace https://greasyfork.org/users/45389
  12. // @version 2019.02.06.001
  13. // @description Adds a Functional Class layer for states that publish ArcGIS FC data.
  14. // @author MapOMatic
  15. // @include /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor\/?.*$/
  16. // @license GNU GPLv3
  17. // @contributionURL https://github.com/WazeDev/Thank-The-Authors
  18. // @require https://greasyfork.org/scripts/39002-bluebird/code/Bluebird.js?version=255146
  19. // @require https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
  20. // @grant GM_xmlhttpRequest
  21. // @connect md.gov
  22. // @connect in.gov
  23. // @connect arcgis.com
  24. // @connect ncdot.gov
  25. // @connect state.mi.us
  26. // @connect dc.gov
  27. // @connect la.gov
  28. // @connect nd.gov
  29. // @connect pa.gov
  30. // @connect oh.us
  31. // @connect iowadot.gov
  32. // @connect ksdot.org
  33. // @connect ky.gov
  34. // @connect shelbycountytn.gov
  35. // @connect illinois.gov
  36. // @connect ny.gov
  37. // @connect utah.gov
  38. // @connect idaho.gov
  39. // @connect wv.gov
  40. // @connect ga.gov
  41. // @connect uga.edu
  42. // @connect nevadadot.com
  43. // @connect sd.gov
  44. // @connect mt.gov
  45. // @connect arkansas.gov
  46. // @connect azdot.gov
  47. // ==/UserScript==
  48.  
  49. (function () {
  50. 'use strict';
  51.  
  52. var _settingsStoreName = 'wme_fc_layer';
  53. var _alertUpdate = false;
  54. var _debugLevel = 0;
  55. var _scriptVersion = GM_info.script.version;
  56. var _scriptVersionChanges = [
  57. GM_info.script.name,
  58. 'v' + _scriptVersion,
  59. '',
  60. 'What\'s New',
  61. '------------------------------',
  62. '' // Add important stuff here when _alertUpdate = true.
  63. ].join('\n');
  64. var _mapLayer = null;
  65. var _isAM = false;
  66. var _uid;
  67. var _settings = {};
  68. var _r;
  69. var _mapLayerZIndex = 334;
  70. var _betaIDs = [103400892];
  71. var _statesHash = {
  72. 'Alabama': 'AL', 'Alaska': 'AK', 'American Samoa': 'AS', 'Arizona': 'AZ', 'Arkansas': 'AR', 'California': 'CA', 'Colorado': 'CO', 'Connecticut': 'CT', 'Delaware': 'DE', 'District of Columbia': 'DC',
  73. 'Federated States Of Micronesia': 'FM', 'Florida': 'FL', 'Georgia': 'GA', 'Guam': 'GU', 'Hawaii': 'HI', 'Idaho': 'ID', 'Illinois': 'IL', 'Indiana': 'IN', 'Iowa': 'IA', 'Kansas': 'KS',
  74. 'Kentucky': 'KY', 'Louisiana': 'LA', 'Maine': 'ME', 'Marshall Islands': 'MH', 'Maryland': 'MD', 'Massachusetts': 'MA', 'Michigan': 'MI', 'Minnesota': 'MN', 'Mississippi': 'MS', 'Missouri': 'MO',
  75. 'Montana': 'MT', 'Nebraska': 'NE', 'Nevada': 'NV', 'New Hampshire': 'NH', 'New Jersey': 'NJ', 'New Mexico': 'NM', 'New York': 'NY', 'North Carolina': 'NC', 'North Dakota': 'ND',
  76. 'Northern Mariana Islands': 'MP', 'Ohio': 'OH', 'Oklahoma': 'OK', 'Oregon': 'OR', 'Palau': 'PW', 'Pennsylvania': 'PA', 'Puerto Rico': 'PR', 'Rhode Island': 'RI', 'South Carolina': 'SC',
  77. 'South Dakota': 'SD', 'Tennessee': 'TN', 'Texas': 'TX', 'Utah': 'UT', 'Vermont': 'VT', 'Virgin Islands': 'VI', 'Virginia': 'VA', 'Washington': 'WA', 'West Virginia': 'WV', 'Wisconsin': 'WI', 'Wyoming': 'WY'
  78. };
  79.  
  80. function reverseStatesHash(stateAbbr) {
  81. for (var stateName in _statesHash) {
  82. if (_statesHash[stateName] === stateAbbr) return stateName;
  83. }
  84. }
  85. var _stateSettings = {
  86. global: {
  87. roadTypes: ['St', 'PS', 'PS2', 'mH', 'MH', 'Ew', 'Rmp', 'Fw'], // Ew = Expressway. For FC's that make it uncertain if they should be MH or FW.
  88. getFeatureRoadType: function (feature, layer) {
  89. var fc = feature.attributes[layer.fcPropName];
  90. return this.getRoadTypeFromFC(fc, layer);
  91. },
  92. getRoadTypeFromFC: function (fc, layer) {
  93. for (var roadType in layer.roadTypeMap) {
  94. if (layer.roadTypeMap[roadType].indexOf(fc) !== -1) {
  95. return roadType;
  96. }
  97. }
  98. return null;
  99. },
  100. isPermitted: function (stateAbbr) { if (_betaIDs.indexOf(_uid) !== -1) return true; var state = _stateSettings[stateAbbr]; if (state.isPermitted) { return state.isPermitted(); } else { return (_r >= 2 && _isAM) || (_r >= 3); } },
  101. getMapLayer: function (stateAbbr, layerID) {
  102. var returnValue;
  103. _stateSettings[stateAbbr].fcMapLayers.forEach(function (layer) {
  104. if (layer.layerID === layerID) {
  105. returnValue = layer;
  106. }
  107. });
  108. return returnValue;
  109. }
  110. },
  111. AZ: {
  112. baseUrl: 'https://gis.azdot.gov/gis/rest/services/AGOL/FunClass_NHS/MapServer/',
  113. defaultColors: { Fw: '#ff00c5', Ew: '#ff00c5', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  114. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
  115. fcMapLayers: [
  116. {
  117. layerID: 8, fcPropName: 'FunctionalClass', idPropName: 'OBJECTID',
  118. outFields: ['OBJECTID', 'FunctionalClass', 'RouteId'],
  119. roadTypeMap: { Fw: [1, 11], Ew: [2, 3, 12], MH: [4, 14], mH: [6, 16], PS: [7, 17, 8, 18], St: [] }, maxRecordCount: 1000, supportsPagination: false
  120. }
  121. ],
  122. getWhereClause: function (context) {
  123. return context.layer.fcPropName + '<>9 OR ' + context.layer.fcPropName + '<>19';
  124. },
  125. getFeatureRoadType: function (feature, layer) {
  126. var roadID = feature.attributes.RouteId.trim().replace(/ +/g, ' ');
  127. var roadNum = parseInt(roadID.substring(2,5));
  128. var fc = parseInt(feature.attributes[layer.fcPropName]);
  129. if (fc === 2) { fc = 4; }
  130. fc = fc % 10;
  131. var azIH = [8, 10, 11, 17, 19, 40];
  132. var isUS = RegExp(/^U\D\d{3}\b/).test(roadID);
  133. var isState = RegExp(/^S\D\d{3}\b/).test(roadID);
  134. var isBiz = RegExp(/^SB\d{3}\b/).test(roadID);
  135. if (fc > 4 && isState && azIH.includes(roadNum) && isBiz) {
  136. fc = 4;
  137. } else if (fc > 4 && isUS) {
  138. fc = isBiz ? 6 : 4;
  139. } else if (fc > 6 && isState) {
  140. fc = isBiz ? 7 : 6;
  141. }
  142. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  143. }
  144. },
  145. AR: {
  146. baseUrl: 'https://gis.arkansas.gov/arcgis/rest/services/FEATURESERVICES/Transportation/FeatureServer/',
  147. defaultColors: { Fw: '#ff00c5', Ew: '#4f33df', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  148. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
  149. fcMapLayers: [
  150. {
  151. layerID: 8, fcPropName: 'FunctionalClass', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FunctionalClass','AH_Route','AH_Section'],
  152. roadTypeMap: { Fw: [1,2], Ew: [], MH: [3], mH: [4], PS: [5, 6], St: [7] }, maxRecordCount: 1000, supportsPagination: false
  153. }
  154. ],
  155. getWhereClause: function (context) {
  156. return null;
  157. },
  158. getFeatureRoadType: function (feature, layer) {
  159. var attr = feature.attributes;
  160. var fc = parseInt(attr[layer.fcPropName]);
  161. var roadID = parseInt(attr.AH_Route);
  162. var usHwys = [49,59,61,62,63,64,65,67,70,71,79,82,165,167,270,271,278,371,412,425];
  163. var isUS = usHwys.includes(roadID);
  164. var isState = roadID < 613;
  165. var isBiz = attr.AH_Section[attr.AH_Section.length - 1] === 'B';
  166. if (fc > 3 && isUS) {
  167. fc = isBiz ? 4 : 3;
  168. } else if (fc > 4 && isState) {
  169. fc = isBiz ? 5 : 4;
  170. }
  171. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  172. }
  173. },
  174. DC: {
  175. baseUrl: 'https://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Transportation_WebMercator/MapServer/',
  176. supportsPagination: false,
  177. defaultColors: { Fw: '#ff00c5', Ew: '#149ece', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  178. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
  179. fetchAllFC: false,
  180. fcMapLayers: [
  181. {
  182. layerID: 48, fcPropName: 'FUNCTIONALCLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCTIONALCLASS'], maxRecordCount: 1000, supportsPagination: false,
  183. roadTypeMap: { Fw: ['Interstate'], Ew: ['Other Freeway and Expressway'], MH: ['Principal Arterial'], mH: ['Minor Arterial'], PS: ['Collector'] }
  184. }
  185. ],
  186. getFeatureRoadType: function (feature, layer) {
  187. if (layer.getFeatureRoadType) {
  188. return layer.getFeatureRoadType(feature);
  189. } else {
  190. return _stateSettings.global.getFeatureRoadType(feature, layer);
  191. }
  192. },
  193. getWhereClause: function (context) {
  194. return null;
  195. }
  196. },
  197. FL: {
  198. baseUrl: 'https://services1.arcgis.com/O1JpcwDW8sjYuddV/ArcGIS/rest/services/Functional_Classification_TDA/FeatureServer/',
  199. supportsPagination: false,
  200. defaultColors: { Fw: '#ff00c5', Ew: '#149ece', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  201. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
  202. fetchAllFC: false,
  203. fcMapLayers: [
  204. {
  205. layerID: 0, fcPropName: 'FUNCLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCLASS'], maxRecordCount: 1000, supportsPagination: false,
  206. roadTypeMap: { Fw: ['01', '11'], Ew: ['02', '12'], MH: ['04', '14'], mH: ['06', '16'], PS: ['07', '08', '17', '18'] }
  207. }
  208. ],
  209. getFeatureRoadType: function (feature, layer) {
  210. if (layer.getFeatureRoadType) {
  211. return layer.getFeatureRoadType(feature);
  212. } else {
  213. return _stateSettings.global.getFeatureRoadType(feature, layer);
  214. }
  215. },
  216. getWhereClause: function (context) {
  217. return null;
  218. }
  219. },
  220. GA: {
  221. baseUrl: 'https://maps.itos.uga.edu/arcgis/rest/services/GDOT/GDOT_FunctionalClass/mapserver/',
  222. supportsPagination: true,
  223. defaultColors: { Fw: '#ff00c5', Ew: '#149ece', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  224. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
  225. fetchAllFC: false,
  226. fcMapLayers: [
  227. { layerID: 0, fcPropName: 'FUNCTIONAL_CLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'], maxRecordCount: 1000, supportsPagination: true, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] } },
  228. { layerID: 1, fcPropName: 'FUNCTIONAL_CLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'], maxRecordCount: 1000, supportsPagination: true, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] } },
  229. { layerID: 2, fcPropName: 'FUNCTIONAL_CLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'], maxRecordCount: 1000, supportsPagination: true, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] } },
  230. { layerID: 3, fcPropName: 'FUNCTIONAL_CLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'], maxRecordCount: 1000, supportsPagination: true, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] } },
  231. { layerID: 4, fcPropName: 'FUNCTIONAL_CLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'], maxRecordCount: 1000, supportsPagination: true, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] } },
  232. { layerID: 5, fcPropName: 'FUNCTIONAL_CLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'], maxRecordCount: 1000, supportsPagination: true, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] } },
  233. { layerID: 6, fcPropName: 'FUNCTIONAL_CLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'], maxRecordCount: 1000, supportsPagination: true, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] } }
  234. ],
  235. getFeatureRoadType: function (feature, layer) {
  236. if (layer.getFeatureRoadType) {
  237. return layer.getFeatureRoadType(feature);
  238. } else {
  239. var attr = feature.attributes;
  240. var fc = attr.FUNCTIONAL_CLASS;
  241. if (attr.SYSTEM_CODE === '1' && fc > 4) {
  242. return _stateSettings.global.getRoadTypeFromFC(4, layer);
  243. } else {
  244. return _stateSettings.global.getFeatureRoadType(feature, layer);
  245. }
  246. }
  247. },
  248. getWhereClause: function (context) {
  249. return null;
  250. }
  251. },
  252. ID: {
  253. baseUrl: 'https://gis.itd.idaho.gov/arcgisprod/rest/services/IPLAN/Functional_Classification/MapServer/',
  254. supportsPagination: false,
  255. defaultColors: { Fw: '#ff00c5', Ew: '#149ece', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  256. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
  257. fetchAllFC: true,
  258. fcMapLayers: [
  259. { layerID: 0, fcPropName: 'FCCODE', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FCCODE'], maxRecordCount: 1000, supportsPagination: false, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] } },
  260. { layerID: 1, fcPropName: 'FCCODE', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FCCODE'], maxRecordCount: 1000, supportsPagination: false, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] } },
  261. { layerID: 2, fcPropName: 'FCCODE', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FCCODE'], maxRecordCount: 1000, supportsPagination: false, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] } },
  262. { layerID: 3, fcPropName: 'FCCODE', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FCCODE'], maxRecordCount: 1000, supportsPagination: false, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] } },
  263. { layerID: 4, fcPropName: 'FCCODE', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FCCODE'], maxRecordCount: 1000, supportsPagination: false, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] } },
  264. { layerID: 5, fcPropName: 'FCCODE', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FCCODE'], maxRecordCount: 1000, supportsPagination: false, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] } }
  265. ],
  266. getFeatureRoadType: function (feature, layer) {
  267. if (layer.getFeatureRoadType) {
  268. return layer.getFeatureRoadType(feature);
  269. } else {
  270. return _stateSettings.global.getFeatureRoadType(feature, layer);
  271. }
  272. },
  273. getWhereClause: function (context) {
  274. return null;
  275. }
  276. },
  277. IL: {
  278. baseUrl: 'https://gis1.dot.illinois.gov/arcgis/rest/services/AdministrativeData/FunctionalClass/MapServer/',
  279. supportsPagination: false,
  280. defaultColors: { Fw: '#ff00c5', Ew: '#ff00c5', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee', CH: '#ff5e0e' },
  281. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
  282. fcMapLayers: [
  283. {
  284. layerID: 0, idPropName: 'OBJECTID', fcPropName: 'FC', outFields: ['FC', 'OBJECTID'],
  285. roadTypeMap: { Fw: ['1'], Ew: ['2'], MH: ['3'], mH: ['4'], PS: ['5', '6'], St: ['7'] }, maxRecordCount: 1000, supportsPagination: false
  286. }
  287. ],
  288. isPermitted: function () { return _r >= 3; },
  289. getWhereClause: function (context) {
  290. return context.mapContext.zoom < 4 ? "FC<>7" : null;
  291. },
  292. getFeatureRoadType: function (feature, layer) {
  293. if (layer.getFeatureRoadType) {
  294. return layer.getFeatureRoadType(feature);
  295. } else {
  296. return _stateSettings.global.getFeatureRoadType(feature, layer);
  297. }
  298. }
  299. },
  300. IN: {
  301. baseUrl: 'https://gis.in.gov/arcgis/rest/services/DOT/INDOT_LTAP/FeatureServer/',
  302. supportsPagination: false,
  303. overrideUrl: '1Sbwc7e6BfHpZWSTfU3_1otXGSxHrdDYcbn7fOf1VjpA',
  304. defaultColors: { Fw: '#ff00c5', Ew: '#149ece', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  305. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []], hideRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  306. fcMapLayers: [
  307. {
  308. layerID: 10, idPropName: 'OBJECTID', fcPropName: 'FUNCTIONAL_CLASS', outFields: ['FUNCTIONAL_CLASS', 'OBJECTID', 'TO_DATE'],
  309. roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] }, maxRecordCount: 100000, supportsPagination: false
  310. }
  311. ],
  312. isPermitted: function () { return true; },
  313. getWhereClauses: function (context) {
  314. },
  315. getWhereClause: function (context) {
  316. var whereParts = [];
  317. if (context.mapContext.zoom < 4) {
  318. whereParts.push(context.layer.fcPropName + '<>7');
  319. }
  320. whereParts.push('TO_DATE IS NULL');
  321. return whereParts.join(' AND ');
  322. },
  323. getFeatureRoadType: function (feature, layer) {
  324. if (layer.getFeatureRoadType) {
  325. return layer.getFeatureRoadType(feature);
  326. } else {
  327. return _stateSettings.global.getFeatureRoadType(feature, layer);
  328. }
  329. }
  330. },
  331. IA: {
  332. baseUrl: 'https://gis.iowadot.gov/public/rest/services/RAMS/Road_Network/MapServer/',
  333. defaultColors: { Fw: '#ff00c5', Ew: '#149ece', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee', PSGr: '#cc6533', StGr: '#e99cb6' },
  334. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  335. fcMapLayers: [
  336. {
  337. layerID: 0, fcPropName: 'FED_FUNCTIONAL_CLASS', idPropName: 'OBJECTID',
  338. outFields: ['OBJECTID', 'FED_FUNCTIONAL_CLASS', 'STATE_ROUTE_NAME_1', 'ACCESS_CONTROL', 'SURFACE_TYPE'],
  339. roadTypeMap: { Fw: [1], MH: [2, 3], mH: [4], PS: [5, 6], St: [7] }, maxRecordCount: 1000, supportsPagination: false
  340. }
  341. ],
  342. getWhereClause: function (context) {
  343. var theWhereClause = "FACILITY_TYPE<>'7'"; // Removed proposed roads
  344. if (context.mapContext.zoom < 4) {
  345. theWhereClause += " AND " + context.layer.fcPropName + "<>'7'";
  346. }
  347. return theWhereClause;
  348. },
  349. getFeatureRoadType: function (feature, layer) {
  350. var attr = feature.attributes;
  351. var fc = parseInt(attr[layer.fcPropName]);
  352. var isFw = attr.ACCESS_CONTROL === 1;
  353. var isUS = RegExp('^STATE OF IOWA, US').test(attr.STATE_ROUTE_NAME_1);
  354. var isState = RegExp('^STATE OF IOWA, IA').test(attr.STATE_ROUTE_NAME_1);
  355. if (isFw) {
  356. fc = 1;
  357. } else if (fc > 3 && isUS) {
  358. fc = 3;
  359. } else if (fc > 4 && isState) {
  360. fc = 4;
  361. }
  362. if (fc > 4 && attr.SURFACE_TYPE === 20) {
  363. return fc < 7 ? 'PSGr' : 'StGr';
  364. } else {
  365. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  366. }
  367. }
  368. },
  369. KS: {
  370. baseUrl: 'http://wfs.ksdot.org/arcgis_web_adaptor/rest/services/Transportation/',
  371. defaultColors: { Fw: '#ff00c5', Ew: '#149ece', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee'},
  372. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  373. fcMapLayers: [
  374. {
  375. layerID: 0, layerPath: 'Non_State_System/MapServer/', idPropName: 'ID2', fcPropName: 'FUNCLASS', outFields: ['FUNCLASS', 'ID2', 'ROUTE_ID'],
  376. roadTypeMap: { Fw: [1], MH: [2, 3], mH: [4], PS: [5, 6], St: [7] }, maxRecordCount: 1000, supportsPagination: false
  377. },
  378. {
  379. layerID: 1, layerPath: 'National_Highway_System/MapServer/', idPropName: 'OBJECTID', fcPropName: 'FUN_CLASS_CD', outFields: ['FUN_CLASS_CD', 'OBJECTID', 'PREFIX', 'ACCESS_CONTROL'],
  380. roadTypeMap: { Fw: [1], MH: [2, 3], mH: [4], PS: [5, 6], St: [7] }, maxRecordCount: 1000, supportsPagination: false
  381. },
  382. {
  383. layerID: 0, layerPath: 'State_System/MapServer/', idPropName: 'OBJECTID', fcPropName: 'FUN_CLASS_CD', outFields: ['FUN_CLASS_CD', 'OBJECTID', 'PREFIX', 'ACCESS_CONTROL'],
  384. roadTypeMap: { Fw: [1], MH: [2, 3], mH: [4], PS: [5, 6], St: [7] }, maxRecordCount: 1000, supportsPagination: false
  385. }
  386. ],
  387. getWhereClause: function (context) {
  388. if (context.mapContext.zoom < 4) {
  389. return context.layer.fcPropName + "<>'7'";
  390. } else {
  391. return null;
  392. }
  393. },
  394. getFeatureRoadType: function (feature, layer) {
  395. var attr = feature.attributes;
  396. var fc = parseInt(attr[layer.fcPropName]);
  397. var roadPrefix = attr.PREFIX;
  398. var isFw = parseInt(attr.ACCESS_CONTROL) === 1;
  399. var isUS = roadPrefix === 'U';
  400. var isState = roadPrefix === 'K';
  401. if (isFw) {
  402. fc = 1;
  403. } else if (fc > 3 && isUS) {
  404. fc = 3;
  405. } else if (fc > 4 && isState) {
  406. fc = 4;
  407. }
  408. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  409. },
  410. },
  411. KY: {
  412. baseUrl: 'https://maps.kytc.ky.gov/arcgis/rest/services/BaseMap/System/MapServer/',
  413. supportsPagination: false,
  414. defaultColors: { Fw: '#ff00c5', Ew: '#ff00c5', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  415. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
  416. fcMapLayers: [
  417. {
  418. layerID: 0, idPropName: 'OBJECTID', fcPropName: 'FC', outFields: ['FC', 'OBJECTID', 'RT_PREFIX', 'RT_SUFFIX'],
  419. roadTypeMap: { Fw: ['1'], Ew: ['2'], MH: ['3'], mH: ['4'], PS: ['5', '6'], St: ['7'] }, maxRecordCount: 1000, supportsPagination: false
  420. }
  421. ],
  422. isPermitted: function () { return true; },
  423. getWhereClause: function (context) {
  424. if (context.mapContext.zoom < 4) {
  425. return context.layer.fcPropName + "<>'7'";
  426. } else {
  427. return null;
  428. }
  429. },
  430. getFeatureRoadType: function (feature, layer) {
  431. if (feature.attributes.RT_PREFIX === 'US') {
  432. var suffix = feature.attributes.RT_SUFFIX;
  433. var type = 'MH';
  434. if (suffix && suffix.indexOf('X') > -1) type = 'mH';
  435. return type;
  436. } else {
  437. return _stateSettings.global.getFeatureRoadType(feature, layer);
  438. }
  439. }
  440. },
  441. LA: {
  442. baseUrl: 'https://giswebnew.dotd.la.gov/arcgis/rest/services/Transportation/LA_RoadwayFunctionalClassification/FeatureServer/',
  443. supportsPagination: false,
  444. defaultColors: { Fw: '#4094ff', Ew: '#ffbf40', MH: '#fb674d', mH: '#6abe40', PS1: '#bf40ec', PS2: '#ffff40', St: '#a2a2a2' },
  445. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  446. fcMapLayers: [
  447. { layerID: 0, fcPropName: 'FunctionalSystem', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FunctionalSystem'], roadTypeMap: { Fw: [1], Ew: ['2', '2a', '2b'], MH: [3], mH: [4], PS1: [5], PS2: [6], St: [7] }, maxRecordCount: 1000, supportsPagination: false },
  448. { layerID: 1, fcPropName: 'FunctionalSystem', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FunctionalSystem'], roadTypeMap: { Fw: [1], Ew: ['2', '2a', '2b'], MH: [3], mH: [4], PS1: [5], PS2: [6], St: [7] }, maxRecordCount: 1000, supportsPagination: false },
  449. { layerID: 2, fcPropName: 'FunctionalSystem', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FunctionalSystem'], roadTypeMap: { Fw: [1], Ew: ['2', '2a', '2b'], MH: [3], mH: [4], PS1: [5], PS2: [6], St: [7] }, maxRecordCount: 1000, supportsPagination: false },
  450. { layerID: 3, fcPropName: 'FunctionalSystem', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FunctionalSystem'], roadTypeMap: { Fw: [1], Ew: ['2', '2a', '2b'], MH: [3], mH: [4], PS1: [5], PS2: [6], St: [7] }, maxRecordCount: 1000, supportsPagination: false },
  451. { layerID: 4, fcPropName: 'FunctionalSystem', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FunctionalSystem'], roadTypeMap: { Fw: [1], Ew: ['2', '2a', '2b'], MH: [3], mH: [4], PS1: [5], PS2: [6], St: [7] }, maxRecordCount: 1000, supportsPagination: false },
  452. { layerID: 5, fcPropName: 'FunctionalSystem', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FunctionalSystem'], roadTypeMap: { Fw: [1], Ew: ['2', '2a', '2b'], MH: [3], mH: [4], PS1: [5], PS2: [6], St: [7] }, maxRecordCount: 1000, supportsPagination: false },
  453. { layerID: 6, fcPropName: 'FunctionalSystem', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FunctionalSystem'], roadTypeMap: { Fw: [1], Ew: ['2', '2a', '2b'], MH: [3], mH: [4], PS1: [5], PS2: [6], St: [7] }, maxRecordCount: 1000, supportsPagination: false }
  454. ],
  455. getWhereClause: function (context) {
  456. if (context.mapContext.zoom < 4) {
  457. return context.layer.fcPropName + "<>'7'"; // OR State_Route LIKE 'US%' OR State_Route LIKE 'LA%'";
  458. } else {
  459. return null;
  460. }
  461. },
  462. getFeatureRoadType: function (feature, layer) {
  463. var fc = feature.attributes[layer.fcPropName];
  464. if (fc === '2a' || fc === '2b') { fc = 2; }
  465. fc = parseInt(fc);
  466. // var stateRoute = feature.attributes.State_Route;
  467. // var isBusiness = /BUS$/.test(stateRoute);
  468. // if (fc > 3 && /^US\s/.test(stateRoute) && !isBusiness) {
  469. // fc = 3;
  470. // } else if (fc > 4 && /^LA\s/.test(stateRoute) && !isBusiness) {
  471. // fc = 4;
  472. // }
  473. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  474. }
  475. },
  476. MD: {
  477. baseUrl: 'https://geodata.md.gov/imap/rest/services/Transportation/MD_HighwayPerformanceMonitoringSystem/MapServer/',
  478. defaultColors: { Fw: '#ff00c5', Ew: '#4f33df', MH: '#149ece', mH: '#4ce600', PS: '#ffff00', St: '#eeeeee' },
  479. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  480. fcMapLayers: [
  481. { layerID: 2, fcPropName: 'FUNCTIONAL_CLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'ID_PREFIX', 'MP_SUFFIX'], roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] }, maxRecordCount: 1000, supportsPagination: false }
  482. ],
  483. getWhereClause: function (context) {
  484. if (context.mapContext.zoom < 4) {
  485. return "(FUNCTIONAL_CLASS < 7 OR ID_PREFIX IN('MD'))";
  486. } else {
  487. return null;
  488. }
  489. },
  490. getFeatureRoadType: function (feature, layer) {
  491. var attr = feature.attributes;
  492. var fc = parseInt(attr.FUNCTIONAL_CLASS);
  493. var isState = attr.ID_PREFIX === 'MD';
  494. var isUS = attr.ID_PREFIX === 'US';
  495. var isBusiness = attr.MP_SUFFIX === 'BU';
  496. if (fc > 3 && isUS) {
  497. fc = isBusiness ? 4 : 3;
  498. } else if (fc > 4 && isState) {
  499. fc = isBusiness ? 5 : 4;
  500. }
  501. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  502. }
  503. },
  504. MI: {
  505. baseUrl: 'https://gisp.mcgi.state.mi.us/arcgis/rest/services/MDOT/NFC/MapServer/',
  506. defaultColors: { Fw: '#ff00c5', Ew: '#149ece', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  507. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  508. fcMapLayers: [
  509. { layerID: 2, idPropName: 'OBJECTID', fcPropName: 'NFC', outFields: ['NFC'], roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] }, maxRecordCount: 1000, supportsPagination: false }
  510. ],
  511. isPermitted: function () { return true; },
  512. getWhereClause: function (context) {
  513. if (context.mapContext.zoom < 4) {
  514. return context.layer.fcPropName + '<>7';
  515. } else {
  516. return null;
  517. }
  518. },
  519. getFeatureRoadType: function (feature, layer) {
  520. if (layer.getFeatureRoadType) {
  521. return layer.getFeatureRoadType(feature);
  522. } else {
  523. return _stateSettings.global.getFeatureRoadType(feature, layer);
  524. }
  525. }
  526. },
  527. MT: {
  528. baseUrl: 'https://app.mdt.mt.gov/arcgis/rest/services/Standard/ROUTES/MapServer/',
  529. defaultColors: { Fw: '#ff00c5', Ew: '#4f33df', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  530. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  531. fcMapLayers: [
  532. { layerID: 0, fcPropName: 'FC' , idPropName: 'OBJECTID', outFields:['OBJECTID', 'FC', 'SIGN_ROUTE', 'ROUTE_NAME'], roadTypeMap:{Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5,6], St: [7]}, maxRecordCount:1000, supportsPagination:false },
  533. { layerID: 1, fcPropName: 'FC' , idPropName: 'OBJECTID', outFields:['OBJECTID', 'FC', 'SIGN_ROUTE', 'ROUTE_NAME'], roadTypeMap:{Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5,6], St: [7]}, maxRecordCount:1000, supportsPagination:false }
  534. ],
  535. isPermitted: function () { return _r >= 3; },
  536. getWhereClause: function (context) {
  537. if (context.mapContext.zoom < 4) {
  538. return context.layer.fcPropName + "<>'LOCAL'";
  539. } else {
  540. return null;
  541. }
  542. },
  543. getFeatureRoadType: function (feature, layer) {
  544. var fc = feature.attributes.FC;
  545. switch (fc) {
  546. case 'PRINCIPAL ARTERIAL - INTERSTATE': fc = 1; break;
  547. case 'PRINCIPAL ARTERIAL - NON-INTERSTATE': fc = 3; break;
  548. case 'MINOR ARTERIAL': fc = 4; break;
  549. case 'MAJOR COLLECTOR':
  550. case 'MINOR COLLECTOR': fc = 5; break;
  551. default: fc = 7;
  552. }
  553. var roadID = feature.attributes.SIGN_ROUTE;
  554. if (!roadID) { roadID = feature.attributes.ROUTE_NAME; }
  555. var isUS = RegExp(/^US \d+/).test(roadID);
  556. var isState = RegExp(/^MONTANA \d+|ROUTE \d+|S \d{3}\b/).test(roadID);
  557. if (fc > 3 && isUS) { fc = 3; }
  558. else if (fc > 4 && isState) { fc = 4; }
  559. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  560. }
  561. },
  562. NV: {
  563. baseUrl: 'https://gis.nevadadot.com/arcgis/rest/services/ArcGISOnline/PublicMaintenanceMap/MapServer/',
  564. defaultColors: { Fw: '#ff00c5', Ew: '#149ece', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  565. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  566. fcMapLayers: [
  567. { layerID: 3, fcPropName: 'FUNC_CODE', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNC_CODE'], roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] }, maxRecordCount: 1000, supportsPagination: false }
  568. ],
  569. getWhereClause: function (context) {
  570. return null;
  571. },
  572. getFeatureRoadType: function (feature, layer) {
  573. return _stateSettings.global.getFeatureRoadType(feature, layer);
  574. }
  575. },
  576. NM: {
  577. baseUrl: 'https://services.arcgis.com/hOpd7wfnKm16p9D9/ArcGIS/rest/services/NMDOT_Functional_Class/FeatureServer/',
  578. defaultColors: { Fw: '#ff00c5', Ew: '#ff00c5', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  579. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
  580. fcMapLayers: [
  581. {
  582. layerID: 0, fcPropName: 'Func_Class', idPropName: 'OBJECTID_1', maxRecordCount: 1000, supportsPagination: false,
  583. outFields: ['OBJECTID_1', 'Func_Class', 'D_RT_ROUTE'], roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] }
  584. }
  585. ],
  586. getWhereClause: function (context) {
  587. return null;
  588. },
  589. getFeatureRoadType: function (feature, layer) {
  590. var fc = parseInt(feature.attributes[layer.fcPropName]);
  591. var roadType = feature.attributes.D_RT_ROUTE.split('-',1).shift();
  592. var isBiz = roadType === 'BL'; // Interstate Business Loop
  593. var isUS = roadType === 'US';
  594. var isState = roadType === 'NM';
  595. console.log([fc,roadType,isBiz,isUS,isState].join(' / '));
  596. if (roadType === 'IX') { fc = 0; }
  597. else if (fc > 3 && (isBiz || isUS)) { fc = 3; }
  598. else if (fc > 4 && isState) { fc = 4; }
  599. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  600. }
  601. },
  602. NY: {//https://gis3.dot.ny.gov/arcgis/rest/services/Basemap/MapServer/21
  603. baseUrl: 'https://gis3.dot.ny.gov/arcgis/rest/services/',
  604. defaultColors: { Fw: '#ff00c5', Ew: '#5f33df', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  605. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
  606. fcMapLayers: [
  607. {
  608. layerID: 'FC/MapServer/1', fcPropName: 'FUNC_CLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNC_CLASS', 'SEGMENT_NAME', 'ROUTE_NO'], roadTypeMap: { Fw: [1, 11], Ew: [2, 12], MH: [4, 14], mH: [6, 16], PS: [7, 8, 17, 18] },
  609. maxRecordCount: 1000, supportsPagination: false
  610. },
  611. { layerID: 'Basemap/MapServer/21', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'SHIELD'], maxRecordCount: 1000, supportsPagination: false }
  612. ],
  613. getWhereClause: function (context) {
  614. if (context.layer.layerID === 'Basemap/MapServer/21') {
  615. return ("SHIELD IN ('C','CT')");
  616. } else {
  617. return null;
  618. }
  619. },
  620. getFeatureRoadType: function (feature, layer) {
  621. var roadType;
  622. if (layer.layerID === 'Basemap/MapServer/21') {
  623. roadType = 'PS';
  624. } else {
  625. roadType = _stateSettings.global.getFeatureRoadType(feature, layer);
  626. var routeNo = feature.attributes.ROUTE_NO;
  627. if (/^NY.*/.test(routeNo)) {
  628. if (roadType === 'PS') roadType = 'mH';
  629. } else if (/^US.*/.test(routeNo)) {
  630. if (roadType === 'PS' || roadType === 'mH') roadType = 'MH';
  631. }
  632. }
  633. return roadType;
  634. }
  635. },
  636. NC: {
  637. baseUrl: 'https://gis11.services.ncdot.gov/arcgis/rest/services/NCDOT_FunctionalClass/MapServer/',
  638. defaultColors: { Fw: '#ff00c5', Rmp: '#999999', Ew: '#5f33df', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  639. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  640. fcMapLayers: [
  641. { layerID: 0, fcPropName: 'FC_TYP_CD', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FC_TYP_CD', 'RTE_1_CLSS_CD'], roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] }, zoomLevels: [3, 4, 5, 6, 7, 8, 9, 10], maxRecordCount: 1000, supportsPagination: false }
  642. //{ layerID:2, fcPropName:'FC_TYP_CD', idPropName:'OBJECTID', outFields:['OBJECTID','FC_TYP_CD','RTE_1_CLSS_CD'], roadTypeMap:{Fw:[1],Ew:[2],MH:[3],mH:[4],PS:[5,6],St:[7]}, zoomLevels:[2], maxRecordCount:1000, supportsPagination:false },
  643. //{ layerID:3, fcPropName:'FC_TYP_CD', idPropName:'OBJECTID', outFields:['OBJECTID','FC_TYP_CD','RTE_1_CLSS_CD'], roadTypeMap:{Fw:[1],Ew:[2],MH:[3],mH:[4],PS:[5,6],St:[7]}, zoomLevels:[0,1], maxRecordCount:1000, supportsPagination:false },
  644. //{ layerID:4, fcPropName:'FC_TYP_CD', idPropName:'OBJECTID', outFields:['OBJECTID','FC_TYP_CD','RTE_1_CLSS_CD'], roadTypeMap:{Fw:[1],Ew:[2],MH:[3],mH:[4],PS:[5,6],St:[7]}, zoomLevels:[], maxRecordCount:1000, supportsPagination:false },
  645. //{ layerID:5, fcPropName:'FC_TYP_CD', idPropName:'OBJECTID', outFields:['OBJECTID','FC_TYP_CD','RTE_1_CLSS_CD'], roadTypeMap:{Fw:[1],Ew:[2],MH:[3],mH:[4],PS:[5,6],St:[7]}, zoomLevels:[], maxRecordCount:1000, supportsPagination:false },
  646. //{ layerID:6, fcPropName:'FC_TYP_CD', idPropName:'OBJECTID', outFields:['OBJECTID','FC_TYP_CD','RTE_1_CLSS_CD'], roadTypeMap:{Fw:[1],Ew:[2],MH:[3],mH:[4],PS:[5,6],St:[7]}, zoomLevels:[], maxRecordCount:1000, supportsPagination:false }
  647. ],
  648. isPermitted: function () { return _r > 1; },
  649. getWhereClause: function (context) {
  650. if (context.mapContext.zoom < 4) {
  651. var clause = '(' + context.layer.fcPropName + " < 7 OR RTE_1_CLSS_CD IN ('I','FED','NC','RMP','US'))";
  652. return clause;
  653. } else {
  654. return null;
  655. }
  656. },
  657. getFeatureRoadType: function (feature, layer) {
  658. var fc = feature.attributes[layer.fcPropName];
  659. var roadType;
  660. switch (this.getHwySys(feature)) {
  661. case 'interstate':
  662. roadType = 'Fw';
  663. break;
  664. case 'us':
  665. roadType = fc <= 2 ? 'Ew' : 'MH';
  666. break;
  667. case 'state':
  668. roadType = fc === 2 ? 'Ew' : (fc === 3 ? 'MH' : 'mH');
  669. break;
  670. case 'ramp':
  671. roadType = 'Rmp';
  672. break;
  673. default:
  674. roadType = fc === 2 ? 'Ew' : (fc === 3 ? 'MH' : (fc === 4 ? 'mH' : (fc <= 6 ? 'PS' : 'St')));
  675. }
  676. return roadType;
  677. },
  678. getHwySys: function (feature) {
  679. var hwySys;
  680. switch (feature.attributes.RTE_1_CLSS_CD) {
  681. case 'I':
  682. hwySys = 'interstate';
  683. break;
  684. case 'FED':
  685. case 'US':
  686. hwySys = 'us';
  687. break;
  688. case 'NC':
  689. hwySys = 'state';
  690. break;
  691. case 'RMP':
  692. hwySys = 'ramp';
  693. break;
  694. default:
  695. hwySys = 'local';
  696. }
  697. return hwySys;
  698. }
  699. },
  700. ND: {
  701. baseUrl: 'https://gis.dot.nd.gov/arcgis/rest/services/external/transinfo/MapServer/',
  702. defaultColors: { Fw: '#ff00c5', Ew: '#149ece', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  703. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  704. fcMapLayers: [
  705. {
  706. layerID: 10, fcPropName: 'FUNCTION_CLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCTION_CLASS'], roadTypeMap: { Fw: ['Interstate'], MH: ['Principal Arterial'], mH: ['Minor Arterial'], PS: ['Major Collector', 'Collector'], St: ['Local'] },
  707. maxRecordCount: 1000, supportsPagination: false
  708. },
  709. {
  710. layerID: 11, fcPropName: 'FUNCTION_CLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCTION_CLASS'], roadTypeMap: { Fw: ['Interstate'], MH: ['Principal Arterial'], mH: ['Minor Arterial'], PS: ['Major Collector', 'Collector'], St: ['Local'] },
  711. maxRecordCount: 1000, supportsPagination: false
  712. },
  713. {
  714. layerID: 12, fcPropName: 'FUNCTION_CLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCTION_CLASS'], roadTypeMap: { PS: ['Major Collector', 'Collector'] },
  715. maxRecordCount: 1000, supportsPagination: false
  716. },
  717. {
  718. layerID: 16, fcPropName: 'SYSTEM_CD', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'SYSTEM_CD', 'SYSTEM_DESC', 'HIGHWAY'], roadTypeMap: { Fw: [1, 11], MH: [2, 14], mH: [6, 7, 16, 19] },
  719. maxRecordCount: 1000, supportsPagination: false
  720. }
  721. ],
  722. getWhereClause: function (context) {
  723. if (context.mapContext.zoom < 4) {
  724. if (context.layer.layerID !== 16) return context.layer.fcPropName + "<>'Local'";
  725. } else {
  726. return null;
  727. }
  728. },
  729. getFeatureRoadType: function (feature, layer) {
  730. return _stateSettings.global.getFeatureRoadType(feature, layer);
  731. }
  732. },
  733. OH: {
  734. baseUrl: 'https://gis.dot.state.oh.us/arcgis/rest/services/TIMS/Roadway_Information/MapServer/',
  735. defaultColors: { Fw: '#ff00c5', Ew: '#4f33df', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  736. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  737.  
  738. fcMapLayers: [
  739. {
  740. layerID: 8, fcPropName: 'FUNCTION_CLASS', idPropName: 'ObjectID', outFields: ['FUNCTION_CLASS', 'ROUTE_TYPE', 'ROUTE_NBR', 'ObjectID'],
  741. maxRecordCount: 1000, supportsPagination: false, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] }
  742. }
  743. ],
  744. isPermitted: function () { return true; },
  745. getWhereClause: function (context) {
  746. if (context.mapContext.zoom < 4) {
  747. var clause = '(' + context.layer.fcPropName + " < 7 OR ROUTE_TYPE IN ('CR','SR','US'))";
  748. return clause;
  749. } else {
  750. return null;
  751. }
  752. },
  753. getFeatureRoadType: function (feature, layer) {
  754. var fc = feature.attributes[layer.fcPropName];
  755. var prefix = feature.attributes.ROUTE_TYPE;
  756. var isUS = prefix === 'US';
  757. var isState = prefix === 'SR';
  758. var isCounty = prefix === 'CR';
  759. if (isUS && fc > 3) { fc = 3; }
  760. if (isState && fc > 4) { fc = 4; }
  761. if (isCounty && fc > 6) { fc = 6; }
  762. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  763. }
  764. },
  765. OK: {
  766. baseUrl: 'https://services6.arcgis.com/RBtoEUQ2lmN0K3GY/arcgis/rest/services/Roadways/FeatureServer/',
  767. defaultColors: { Fw: '#ff00c5', Ew: '#4f33df', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  768. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  769. fcMapLayers: [
  770. {
  771. layerID: 0, fcPropName: 'NFC', idPropName: 'OBJECTID', outFields: ['F_PRIMARY_', 'NFC', 'OBJECTID', 'ROUTE_CLAS', 'ACCESS_CON'],
  772. maxRecordCount: 1000, supportsPagination: false, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] }
  773. }
  774. ],
  775. getWhereClause: function (context) {
  776. if (context.mapContext.zoom < 4) {
  777. var clause = '(' + context.layer.fcPropName + " < 7 OR ROUTE_CLAS IN ('U','S','I'))";
  778. return clause;
  779. } else {
  780. return null;
  781. }
  782. },
  783. getFeatureRoadType: function (feature, layer) {
  784. var fc = feature.attributes[layer.fcPropName];
  785. var route = (feature.attributes.F_PRIMARY_ || '').trim();
  786. var isBusinessOrSpur = /BUS$|SPR$/i.test(route);
  787. var prefix = isBusinessOrSpur ? route.substring(0, 1) : feature.attributes.ROUTE_CLAS;
  788. var isFw = parseInt(feature.attributes.ACCESS_CON) === 1;
  789. var isInterstate = prefix === 'I';
  790. var isUS = prefix === 'U';
  791. var isState = prefix === 'S';
  792. if (isFw) { fc = 1; }
  793. else if (fc > 3 && ((isUS && !isBusinessOrSpur) || (isInterstate && isBusinessOrSpur))) { fc = 3; }
  794. else if (fc > 4 && ((isUS && isBusinessOrSpur) || (isState && !isBusinessOrSpur))) { fc = 4; }
  795. else if (fc > 5 && isState && isBusinessOrSpur) { fc = 5; }
  796. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  797. }
  798. },
  799. PA: {
  800. baseUrl: 'https://www.pdarcgissvr.pa.gov/penndotgis/rest/services/PennShare/PennShare/MapServer/',
  801. supportsPagination: false,
  802. defaultColors: { Fw: '#00ffff', Ew: '#732500', MH: '#ff0000', mH: '#00ff00', PS: '#b724ff', PS2: '#f3f300', St: '#ff9700' },
  803. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  804. isPermitted: function () { return _r >= 3; },
  805. fcMapLayers: [
  806. {
  807. layerID: 3, features: new Map(), fcPropName: 'FUNC_CLS', idPropName: 'MSLINK', outFields: ['MSLINK', 'FUNC_CLS'],
  808. maxRecordCount: 1000, supportsPagination: false, roadTypeMap: { Fw: ['01', '11'], Ew: ['12'], MH: ['02', '14'], mH: ['06', '16'], PS: ['07', '08', '17'], St: ['09', '19'] }
  809. }
  810. ],
  811. getWhereClause: function (context) {
  812. return null;
  813. },
  814. getFeatureRoadType: function (feature, layer) {
  815. if (layer.getFeatureRoadType) {
  816. return layer.getFeatureRoadType(feature);
  817. } else {
  818. var fc = feature.attributes[layer.fcPropName];
  819. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  820. }
  821. }
  822. },
  823. SC: {
  824. baseUrl: 'https://services1.arcgis.com/VaY7cY9pvUYUP1Lf/arcgis/rest/services/Functional_Class/FeatureServer/',
  825. defaultColors: { Fw: '#ff00c5', Ew: '#4f33df', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  826. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  827. fcMapLayers: [
  828. {
  829. layerID: 0, fcPropName: 'FC_GIS' , idPropName: 'FID', outFields:['FID', 'FC_GIS', 'ROUTE_LRS'],
  830. maxRecordCount:1000, supportsPagination:false, roadTypeMap:{Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5,6], St: [7]}
  831. }
  832. ],
  833. isPermitted: function () { return _r >= 3; },
  834. getWhereClause: function (context) {
  835. return null;
  836. },
  837. getFeatureRoadType: function (feature, layer) {
  838. var roadID = feature.attributes.ROUTE_LRS;
  839. var roadType = parseInt(roadID.slice(3,4));
  840. var isFw = roadType === 1;
  841. var isUS = roadType === 2;
  842. var isState = roadType === 4;
  843. var isBus = parseInt(roadID.slice(-2,-1)) === 7;
  844. var fc = 7;
  845. switch(feature.attributes[layer.fcPropName]) {
  846. case 'INT': fc = 1; break;
  847. case 'EXP': fc = 2; break;
  848. case 'PRA': fc = 3; break;
  849. case 'MIA': fc = 4; break;
  850. case 'MAC':
  851. case 'MIC': fc = 5; break;
  852. }
  853. if (fc > 1 && isFw) {
  854. fc = 1;
  855. } else if (fc > 3 && isUS) {
  856. fc = (isBus ? 4 : 3);
  857. } else if (fc > 4 && isState) {
  858. fc = (isBus ? 5 : 4);
  859. }
  860. if (layer.getFeatureRoadType) {
  861. return layer.getFeatureRoadType(feature);
  862. } else {
  863. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  864. }
  865. }
  866. },
  867. SD: {
  868. baseUrl: 'https://arcgis.sd.gov/arcgis/rest/services/DOT/LocalRoads/MapServer/',
  869. defaultColors: { Fw: '#ff00c5', Ew: '#149ece', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee', PSGr: '#cc6533', StGr: '#e99cb6' },
  870. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  871. fcMapLayers: [{
  872. layerID: 1, fcPropName: 'FUNC_CLASS', idPropName: 'OBJECTID', maxRecordCount: 1000, supportsPagination: false,
  873. outFields: ['OBJECTID', 'FUNC_CLASS', 'SURFACE_TYPE', 'ROADNAME'],
  874. roadTypeMap: { Fw: [1, 11], Ew: [2, 12], MH: [4, 14], mH: [6, 16], PS: [7, 8, 17], St: [9, 19] }
  875. }
  876. ],
  877. getWhereClause: function (context) {
  878. if (context.mapContext.zoom < 4) {
  879. return context.layer.fcPropName + "<>19 AND " + context.layer.fcPropName + "<>9";
  880. } else {
  881. return null;
  882. }
  883. },
  884. getFeatureRoadType: function (feature, layer) {
  885. var attr = feature.attributes;
  886. var fc = parseInt(attr[layer.fcPropName]) % 10;
  887. var isFw = attr.ACCESS_CONTROL === 1;
  888. var isUS = RegExp('^US HWY ', 'i').test(attr.ROADNAME);
  889. var isState = RegExp('^SD HWY ', 'i').test(attr.ROADNAME);
  890. var isBus = RegExp('^(US|SD) HWY .* (E|W)?(B|L)$', 'i').test(attr.ROADNAME);
  891. var isPaved = parseInt(attr.SURFACE_TYPE) > 5;
  892. if (isFw) {
  893. fc = 1;
  894. } else if (fc > 4 && isUS) {
  895. fc = (isBus ? 6 : 4);
  896. } else if (fc > 6 && isState) {
  897. fc = (isBus ? 7 : 6);
  898. }
  899. if (fc > 6 && !isPaved) {
  900. return fc < 9 ? 'PSGr' : 'StGr';
  901. } else {
  902. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  903. }
  904. }
  905. },
  906. TN: {
  907. // NOTE: DUE TO ERRORS FROM THE SHELBY COUNTY SERVER, FC IS NOT WORKING PROPERLY HERE YET (9/23/2016)
  908. baseUrl: 'https://testuasiportal.shelbycountytn.gov/arcgis/rest/services/MPO/Webmap_2015_04_20_TMPO/MapServer/',
  909.  
  910. // TODO: UPDATE COLORS TO MATCH ORIGINAL TN FC MAP COLORS.
  911. defaultColors: { Fw: '#ff00c5', Ew: '#4f33df', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', PS2: '#cfae0e', St: '#eeeeee' },
  912. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
  913. fcMapLayers: [
  914. { layerID: 17, fcPropName: 'FuncClass', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FuncClass'], maxRecordCount: 1000, supportsPagination: false, roadTypeMap: { Fw: [1, 11], Ew: [2, 12], MH: [4, 14], mH: [6, 16], PS: [7, 17], PS2: [8, 18], St: [9, 19] } }
  915. ],
  916. getWhereClause: function (context) {
  917. if (context.mapContext.zoom < 4) {
  918. return context.layer.fcPropName + ' NOT IN (9,19)';
  919. } else {
  920. return null;
  921. }
  922. },
  923. getFeatureRoadType: function (feature, layer) {
  924. if (layer.getFeatureRoadType) {
  925. return layer.getFeatureRoadType(feature);
  926. } else {
  927. var fc = feature.attributes[layer.fcPropName];
  928. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  929. }
  930. }
  931. },
  932. TX: {
  933. baseUrl: 'https://services.arcgis.com/KTcxiTD9dsQw4r7Z/ArcGIS/rest/services/TxDOT_Functional_Classification/FeatureServer/',
  934. defaultColors: { Fw: '#ff00c5', Ew: '#4f33df', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  935. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
  936. fcMapLayers: [
  937. { layerID: 0, fcPropName: 'F_SYSTEM', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'F_SYSTEM', 'RTE_PRFX'], maxRecordCount: 1000, supportsPagination: false, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] } }
  938. ],
  939. getWhereClause: function (context) {
  940. var where = " F_SYSTEM IS NOT NULL AND RTE_PRFX IS NOT NULL";
  941. if (context.mapContext.zoom < 4) {
  942. where += ' AND ' + context.layer.fcPropName + " <> 7";
  943. }
  944. return where;
  945. },
  946. getFeatureRoadType: function (feature, layer) {
  947. // On-System:
  948. // IH=Interstate BF=Business FM
  949. // US=US Highway FM=Farm to Mkt
  950. // UA=US Alt. RM=Ranch to Mkt
  951. // UP=US Spur RR=Ranch Road
  952. // SH=State Highway PR=Park Road
  953. // SA=State Alt. RE=Rec Road
  954. // SL=State Loop RP=Rec Rd Spur
  955. // SS=State Spur FS=FM Spur
  956. // BI=Business IH RS=RM Spur
  957. // BU=Business US RU=RR Spur
  958. // BS=Business State PA=Principal Arterial
  959. // Off-System:
  960. // TL=Off-System Tollroad CR=County Road
  961. // FC=Func. Classified St. LS=Local Street
  962. if (layer.getFeatureRoadType) {
  963. return layer.getFeatureRoadType(feature);
  964. } else {
  965. var fc = feature.attributes[layer.fcPropName];
  966. var type = feature.attributes.RTE_PRFX.substring(0, 2).toUpperCase();
  967. if (type === 'IH' && fc > 1) {
  968. fc = 1;
  969. } else if ((type === 'US' || type === 'BI' || type === 'UA') && fc > 3) {
  970. fc = 3;
  971. } else if ((type === 'UP' || type === 'BU' || type === 'SH' || type === 'SA') && fc > 4) {
  972. fc = 4;
  973. } else if ((type === 'SL' || type === 'SS' || type === 'BS') && fc > 6) {
  974. fc = 6;
  975. }
  976. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  977. }
  978. },
  979. isPermitted: function () { return _r >= 1; }
  980. },
  981. UT: {
  982. baseUrl: 'https://maps.udot.utah.gov/arcgis/rest/services/Functional_Class/MapServer/',
  983. defaultColors: { Fw: '#ff00c5', Ew: '#4f33df', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  984. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  985. fcMapLayers: [
  986. {
  987. layerID: 0, fcPropName: 'FC_CODE', idPropName: 'OBJECTID', outFields: ['*'/*'OBJECTID','FC_CODE'*/], roadTypeMap: { Fw: [1], Ew: [2, 20], MH: [3, 30], mH: [4, 40], PS: [5, 50, 6, 60], St: [7, 77] },
  988. maxRecordCount: 1000, supportsPagination: false
  989. }
  990. ],
  991. getWhereClause: function (context) {
  992. var clause = context.layer.fcPropName + '<=7';
  993. if (context.mapContext.zoom < 4) {
  994. clause += ' OR ' + context.layer.fcPropName + '<7';
  995. }
  996. return clause;
  997. },
  998. getFeatureRoadType: function (feature, layer) {
  999. var routeId = feature.attributes.ROUTE_ID;
  1000. var fc = feature.attributes.FC_CODE;
  1001. if ([6, 40, 50, 89, 91, 163, 189, 191, 491].indexOf(routeId) > -1 && fc > 3) {
  1002. // US highway
  1003. fc = 3;
  1004. } else if (routeId <= 491 && fc > 4) {
  1005. // State highway
  1006. fc = 4;
  1007. }
  1008. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  1009. }
  1010. },
  1011. VA: {
  1012. baseUrl: 'https://services.arcgis.com/p5v98VHDX9Atv3l7/arcgis/rest/services/FC_2014_FHWA_Submittal1/FeatureServer/',
  1013. defaultColors: { Fw: '#ff00c5', Ew: '#ff00c5', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  1014. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  1015. fcMapLayers: [
  1016. { layerID: 0, fcPropName: 'FUNCTIONAL_CLASS_ID', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'FUNCTIONAL_CLASS_ID', 'RTE_NM'], maxRecordCount: 2000, supportsPagination: true, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] } },
  1017. { layerID: 1, fcPropName: 'STATE_FUNCT_CLASS_ID', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'STATE_FUNCT_CLASS_ID', 'RTE_NM', 'ROUTE_NO'], maxRecordCount: 2000, supportsPagination: true, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] } },
  1018. { layerID: 3, fcPropName: 'TMPD_FC', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'TMPD_FC', 'RTE_NM'], maxRecordCount: 2000, supportsPagination: true, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] } }
  1019. ],
  1020. srExceptions: [217, 302, 303, 305, 308, 310, 313, 314, 315, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 339, 341, 342, 343, 344, 345, 346, 347, 348, 350, 353, 355, 357, 358, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 396, 397, 398, 399, 785, 895],
  1021. getWhereClause: function (context) {
  1022. if (context.mapContext.zoom < 4) {
  1023. return context.layer.fcPropName + '<>7';
  1024. } else {
  1025. //NOTE: As of 9/14/2016 there does not appear to be any US/SR/VA labeled routes with FC = 7.
  1026. return null;
  1027. }
  1028. },
  1029. getFeatureRoadType: function (feature, layer) {
  1030. if (layer.getFeatureRoadType) {
  1031. return layer.getFeatureRoadType(feature);
  1032. } else {
  1033. var fc = parseInt(feature.attributes[layer.fcPropName]);
  1034. var rtName = feature.attributes.RTE_NM;
  1035. var match = /^R-VA\s*(US|VA|SR)(\d{5})..(BUS)?/.exec(rtName);
  1036. var isBusiness = (match && (match !== null) && (match[3] === 'BUS'));
  1037. var isState = (match && (match !== null) && (match[1] === 'VA' || match[1] === 'SR'));
  1038. var rtNum = parseInt((layer.layerID === 1) ? feature.attributes.ROUTE_NO : (match ? match[2] : 99999));
  1039. var rtPrefix = match && match[1];
  1040. if (fc > 3 && rtPrefix === 'US') {
  1041. fc = isBusiness ? 4 : 3;
  1042. } else if (isState && fc > 4 && this.srExceptions.indexOf(rtNum) === -1 && rtNum < 600) {
  1043. fc = isBusiness ? 5 : 4;
  1044. }
  1045. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  1046. }
  1047. }
  1048. },
  1049. WV: {
  1050. baseUrl: 'https://gis.transportation.wv.gov/arcgis/rest/services/Roads_And_Highways/Publication_LRS/MapServer/',
  1051. defaultColors: { Fw: '#ff00c5', Ew: '#ff00c5', MH: '#149ece', mH: '#4ce600', PS: '#cfae0e', St: '#eeeeee' },
  1052. zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
  1053. fcMapLayers: [
  1054. { layerID: 35, fcPropName: 'NAT_FUNCTIONAL_CLASS', idPropName: 'OBJECTID', outFields: ['OBJECTID', 'NAT_FUNCTIONAL_CLASS', 'ROUTE_ID'], maxRecordCount: 1000, supportsPagination: true, roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] } }
  1055. ],
  1056. getWhereClause: function (context) {
  1057. if (context.mapContext.zoom < 4) {
  1058. return context.layer.fcPropName + ' NOT IN(9,19)';
  1059. } else {
  1060. return null;
  1061. }
  1062. },
  1063. getFeatureRoadType: function (feature, layer) {
  1064. if (layer.getFeatureRoadType) {
  1065. return layer.getFeatureRoadType(feature);
  1066. } else {
  1067. var fcCode = feature.attributes[layer.fcPropName];
  1068. var fc = fcCode;
  1069. if (fcCode === 11) fc = 1;
  1070. else if (fcCode === 4 || fcCode === 12) fc = 2;
  1071. else if (fcCode === 2 || fcCode === 14) fc = 3;
  1072. else if (fcCode === 6 || fcCode === 16) fc = 4;
  1073. else if (fcCode === 7 || fcCode === 17 || fcCode === 8 || fcCode === 18) fc = 5;
  1074. else fc = 7;
  1075. var id = feature.attributes.ROUTE_ID;
  1076. var prefix = id.substr(2, 1);
  1077. var isInterstate = false;
  1078. var isUS = false;
  1079. var isState = false;
  1080. switch (prefix) {
  1081. case '1':
  1082. isInterstate = true;
  1083. break;
  1084. case '2':
  1085. isUS = true;
  1086. break;
  1087. case '3':
  1088. isState = true;
  1089. break;
  1090. }
  1091. if (fc > 1 && isInterstate)
  1092. fc = 1;
  1093. else if (fc > 3 && isUS)
  1094. fc = 3;
  1095. else if (fc > 4 && isState)
  1096. fc = 4;
  1097. return _stateSettings.global.getRoadTypeFromFC(fc, layer);
  1098. }
  1099. }
  1100. }
  1101. };
  1102.  
  1103. function log(message, level) {
  1104. if (message && (!level || (level <= _debugLevel))) {
  1105. console.log('FC Layer: ', message);
  1106. }
  1107. }
  1108.  
  1109. function dynamicSort(property) {
  1110. var sortOrder = 1;
  1111. if (property[0] === "-") {
  1112. sortOrder = -1;
  1113. property = property.substr(1);
  1114. }
  1115. return function (a, b) {
  1116. var props = property.split('.');
  1117. props.forEach(function (prop) {
  1118. a = a[prop];
  1119. b = b[prop];
  1120. });
  1121. var result = (a < b) ? -1 : (a > b) ? 1 : 0;
  1122. return result * sortOrder;
  1123. };
  1124. }
  1125.  
  1126. function dynamicSortMultiple() {
  1127. /*
  1128. * save the arguments object as it will be overwritten
  1129. * note that arguments object is an array-like object
  1130. * consisting of the names of the properties to sort by
  1131. */
  1132. var props = arguments;
  1133. if (arguments[0] && Array.isArray(arguments[0])) {
  1134. props = arguments[0];
  1135. }
  1136. return function (obj1, obj2) {
  1137. var i = 0, result = 0, numberOfProperties = props.length;
  1138. /* try getting a different result from 0 (equal)
  1139. * as long as we have extra properties to compare
  1140. */
  1141. while (result === 0 && i < numberOfProperties) {
  1142. result = dynamicSort(props[i])(obj1, obj2);
  1143. i++;
  1144. }
  1145. return result;
  1146. };
  1147. }
  1148.  
  1149. function generateUUID() {
  1150. var d = new Date().getTime();
  1151. var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
  1152. var r = (d + Math.random() * 16) % 16 | 0;
  1153. d = Math.floor(d / 16);
  1154. return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
  1155. });
  1156. return uuid;
  1157. }
  1158.  
  1159. function loadSettingsFromStorage() {
  1160. var loadedSettings = $.parseJSON(localStorage.getItem(_settingsStoreName));
  1161. var defaultSettings = {
  1162. lastVersion: null,
  1163. layerVisible: true,
  1164. activeStateAbbr: 'ALL',
  1165. hideStreet: false
  1166. };
  1167. _settings = loadedSettings ? loadedSettings : defaultSettings;
  1168. for (var prop in defaultSettings) {
  1169. if (!_settings.hasOwnProperty(prop)) {
  1170. _settings[prop] = defaultSettings[prop];
  1171. }
  1172. }
  1173. }
  1174.  
  1175. function saveSettingsToStorage() {
  1176. if (localStorage) {
  1177. _settings.lastVersion = _scriptVersion;
  1178. _settings.layerVisible = _mapLayer.visibility;
  1179. localStorage.setItem(_settingsStoreName, JSON.stringify(_settings));
  1180. log('Settings saved', 1);
  1181. }
  1182. }
  1183.  
  1184. function getLineWidth() {
  1185. return 12 * Math.pow(1.15, (W.map.getZoom() - 1));
  1186. }
  1187.  
  1188. function sortArray(array) {
  1189. array.sort(function (a, b) { if (a < b) return -1; if (a > b) return 1; else return 0; });
  1190. }
  1191.  
  1192. function getVisibleStateAbbrs() {
  1193. var visibleStates = [];
  1194. W.model.states.additionalInfo.forEach(function (state) {
  1195. var stateAbbr = _statesHash[state.name];
  1196. var activeStateAbbr = _settings.activeStateAbbr;
  1197. if (_stateSettings[stateAbbr] && _stateSettings.global.isPermitted(stateAbbr) && (!activeStateAbbr || activeStateAbbr === 'ALL' || activeStateAbbr === stateAbbr)) {
  1198. visibleStates.push(stateAbbr);
  1199. }
  1200. });
  1201. return visibleStates;
  1202. }
  1203.  
  1204. function getAsync(url, context) {
  1205. return new Promise(function (resolve, reject) {
  1206. GM_xmlhttpRequest({
  1207. context: context, method: "GET", url: url,
  1208. onload: function (res) {
  1209. if (res.status.toString() === '200') {
  1210. resolve({ responseText: res.responseText, context: context });
  1211. } else {
  1212. reject({ responseText: res.responseText, context: context });
  1213. }
  1214. },
  1215. onerror: function () {
  1216. reject(Error("Network Error"));
  1217. }
  1218. });
  1219. });
  1220. }
  1221. function wait(ms) {
  1222. var start = new Date().getTime();
  1223. var end = start;
  1224. while (end < start + ms) {
  1225. end = new Date().getTime();
  1226. }
  1227. }
  1228. function getUrl(context, queryType, queryParams) {
  1229. var extent = context.mapContext.extent,
  1230. zoom = context.mapContext.zoom,
  1231. layer = context.layer,
  1232. state = context.state;
  1233.  
  1234. var whereParts = [];
  1235. var geometry = { xmin: extent.left, ymin: extent.bottom, xmax: extent.right, ymax: extent.top, spatialReference: { wkid: 102100, latestWkid: 3857 } };
  1236. var geometryStr = JSON.stringify(geometry);
  1237. var stateWhereClause = state.getWhereClause(context);
  1238. var layerPath = layer.layerPath || '';
  1239. var url = state.baseUrl + layerPath + layer.layerID + '/query?geometry=' + encodeURIComponent(geometryStr);
  1240.  
  1241. if (queryType === 'countOnly') {
  1242. url += '&returnCountOnly=true';
  1243. } else if (queryType === 'idsOnly') {
  1244. url += '&returnIdsOnly=true';
  1245. } else if (queryType === 'paged') {
  1246. // TODO
  1247. } else {
  1248. url += '&returnGeometry=true&maxAllowableOffset=' + state.zoomSettings.maxOffset[zoom];
  1249. url += '&outFields=' + encodeURIComponent(layer.outFields.join(','));
  1250. if (queryType === 'idRange') {
  1251. var idPropName = context.layer.idPropName;
  1252. whereParts.push('(' + queryParams.idFieldName + '>=' + queryParams.range[0] + ' AND ' + queryParams.idFieldName + '<=' + queryParams.range[1] + ')');
  1253. }
  1254. }
  1255. if (stateWhereClause) whereParts.push(stateWhereClause);
  1256. if (whereParts.length > 0) url += '&where=' + encodeURIComponent(whereParts.join(' AND '));
  1257. url += '&spatialRel=esriSpatialRelIntersects&geometryType=esriGeometryEnvelope&inSR=102100&outSR=3857&f=json';
  1258. //wait(500); // I don't know why this was in the code. Leaving it commented here just in case it was a hack to solve some issue.
  1259. return url;
  1260. }
  1261.  
  1262. function convertFcToRoadTypeVectors(feature, state, stateAbbr, layer, zoom) {
  1263. var roadType = state.getFeatureRoadType(feature, layer);
  1264. log(feature, 3);
  1265. var zIndex = _stateSettings.global.roadTypes.indexOf(roadType) * 100;
  1266. var vectors = [];
  1267. var lineFeatures = [];
  1268. var attr = {
  1269. //fcFeatureUniqueId: stateAbbr + '-' + layer.layerID + '-' + feature.attributes[layer.idPropName],
  1270. //fcFeatureId: feature.attributes[layer.idPropName],
  1271. state: stateAbbr,
  1272. layerID: layer.layerID,
  1273. roadType: roadType,
  1274. dotAttributes: $.extend({}, feature.attributes),
  1275. color: state.defaultColors[roadType],
  1276. strokeWidth: getLineWidth,
  1277. zIndex: zIndex
  1278. };
  1279.  
  1280. feature.geometry.paths.forEach(function (path) {
  1281. var pointList = [];
  1282. var newPoint = null;
  1283. var lastPoint = null;
  1284. path.forEach(function (point) {
  1285. pointList.push(new OL.Geometry.Point(point[0], point[1]));
  1286. });
  1287. var vectorFeature = new OL.Feature.Vector(new OL.Geometry.LineString(pointList), attr);
  1288. vectors.push(vectorFeature);
  1289. });
  1290.  
  1291. return vectors;
  1292. }
  1293.  
  1294. function fetchLayerFC(context) {
  1295. var url = getUrl(context, 'idsOnly');
  1296. log(url, 2);
  1297. if (!context.parentContext.cancel) {
  1298. return getAsync(url, context).bind(context).then(function (res) {
  1299. var ids = $.parseJSON(res.responseText);
  1300. if (!ids.objectIds) ids.objectIds = [];
  1301. sortArray(ids.objectIds);
  1302. log(ids, 2);
  1303. return ids;
  1304. }).then(function (res) {
  1305. var context = this;
  1306. var idRanges = [];
  1307. if (res.objectIds) {
  1308. var len = res.objectIds ? res.objectIds.length : 0;
  1309. var currentIndex = 0;
  1310. var offset = Math.min(this.layer.maxRecordCount, 1000);
  1311. while (currentIndex < len) {
  1312. var nextIndex = currentIndex + offset;
  1313. if (nextIndex >= len) nextIndex = len - 1;
  1314. idRanges.push({ range: [res.objectIds[currentIndex], res.objectIds[nextIndex]], idFieldName: res.objectIdFieldName });
  1315. currentIndex = nextIndex + 1;
  1316. }
  1317. log(context.layer.layerID, 2);
  1318. log(idRanges, 2);
  1319. }
  1320. return idRanges;
  1321. }).map(function (idRange) {
  1322. var context = this;
  1323. if (!context.parentContext.cancel) {
  1324. var url = getUrl(this, 'idRange', idRange);
  1325. log(url, 2);
  1326. return getAsync(url, context).then(function (res) {
  1327. var context = res.context;
  1328. if (!context.parentContext.cancel) {
  1329. var features = $.parseJSON(res.responseText).features;
  1330. // if (context.parentContext.callCount === 0 ) {
  1331. // _mapLayer.removeAllFeatures();
  1332. // }
  1333. context.parentContext.callCount++;
  1334. log('Feature Count=' + (features ? features.length : 0), 2);
  1335. features = features ? features : [];
  1336. var vectors = [];
  1337. features.forEach(function (feature) {
  1338. if (!res.context.parentContext.cancel) {
  1339. var vector = convertFcToRoadTypeVectors(feature, context.state, context.stateAbbr, context.layer, context.mapContext.zoom);
  1340. //var fcFeatureUniqueId = vector[0].attributes.fcFeatureUniqueId;
  1341. //context.parentContext.addedFcFeatureUniqueIds.push(fcFeatureUniqueId);
  1342. if (/*!context.parentContext.existingFcFeatureUniqueIds[fcFeatureUniqueId] &&*/ !(vector[0].attributes.roadType === 'St' && _settings.hideStreet)) {
  1343. vectors.push(vector);
  1344. }
  1345. }
  1346. });
  1347. return vectors;
  1348. }
  1349. });
  1350. } else {
  1351. log('Async call cancelled', 1);
  1352. }
  1353. });
  1354. }
  1355. }
  1356.  
  1357. function fetchStateFC(context) {
  1358. var state = _stateSettings[context.stateAbbr];
  1359. var contexts = [];
  1360. state.fcMapLayers.forEach(function (layer) {
  1361. contexts.push({ parentContext: context.parentContext, layer: layer, state: state, stateAbbr: context.stateAbbr, mapContext: context.mapContext });
  1362. });
  1363. return Promise.map(contexts, function (context) {
  1364. return fetchLayerFC(context);
  1365. });
  1366. }
  1367.  
  1368. var _lastPromise = null;
  1369. var _lastContext = null;
  1370. var _fcCallCount = 0;
  1371. function fetchAllFC() {
  1372. if (!_mapLayer.visibility) return;
  1373.  
  1374. if (_lastPromise) { _lastPromise.cancel(); }
  1375. $('#fc-loading-indicator').text('Loading FC...');
  1376.  
  1377. var mapContext = { zoom: W.map.getZoom(), extent: W.map.getExtent() };
  1378. var contexts = [];
  1379. var parentContext = { callCount: 0,/*existingFcFeatureUniqueIds:{}, addedFcFeatureUniqueIds:[],*/ startTime: Date.now() };
  1380. // _mapLayer.features.forEach(function(vectorFeature) {
  1381. // var fcFeatureUniqueId = vectorFeature.attributes.fcFeatureUniqueId;
  1382. // var existingFcFeatureUniqueIdArray = parentContext.existingFcFeatureUniqueIds[fcFeatureUniqueId];
  1383. // if (!existingFcFeatureUniqueIdArray) {
  1384. // existingFcFeatureUniqueIdArray = [];
  1385. // parentContext.existingFcFeatureUniqueIds[fcFeatureUniqueId] = existingFcFeatureUniqueIdArray;
  1386. // }
  1387. // existingFcFeatureUniqueIdArray.push(vectorFeature);
  1388. // });
  1389. if (_lastContext) _lastContext.cancel = true;
  1390. _lastContext = parentContext;
  1391. getVisibleStateAbbrs().forEach(function (stateAbbr) {
  1392. contexts.push({ parentContext: parentContext, stateAbbr: stateAbbr, mapContext: mapContext });
  1393. });
  1394. var map = Promise.map(contexts, function (context) {
  1395. return fetchStateFC(context);
  1396. }).bind(parentContext).then(function (statesVectorArrays) {
  1397. if (!this.cancel) {
  1398. _mapLayer.removeAllFeatures();
  1399. statesVectorArrays.forEach(function (vectorsArray) {
  1400. vectorsArray.forEach(function (vectors) {
  1401. vectors.forEach(function (vector) {
  1402. vector.forEach(function (vectorFeature) {
  1403. _mapLayer.addFeatures(vectorFeature);
  1404. });
  1405. });
  1406. });
  1407. });
  1408. //buildTable();
  1409. // for(var fcFeatureUniqueId in this.existingFcFeatureUniqueIds) {
  1410. // if(this.addedFcFeatureUniqueIds.indexOf(fcFeatureUniqueId) === -1) {
  1411. // if (!this.cancel) _mapLayer.removeFeatures(this.existingFcFeatureUniqueIds[fcFeatureUniqueId]);
  1412. // }
  1413. // }
  1414. log('TOTAL RETRIEVAL TIME = ' + (Date.now() - parentContext.startTime), 1);
  1415. log(statesVectorArrays, 1);
  1416. }
  1417. return statesVectorArrays;
  1418. }).catch(function (e) {
  1419. $('#fc-loading-indicator').text('FC Error! (check console for details)');
  1420. log(e, 0);
  1421. }).finally(function () {
  1422. _fcCallCount -= 1;
  1423. if (_fcCallCount === 0) {
  1424. $('#fc-loading-indicator').text('');
  1425. }
  1426. });
  1427.  
  1428. let mapState = W.model.states.top;
  1429. let selState = $('#fcl-state-select').val();
  1430. if (mapState && mapState.name === 'Illinois' && (selState === 'ALL' || selState === 'IL') && !_settings.ilFcWarning) {
  1431. _settings.ilFcWarning = true;
  1432. saveSettingsToStorage();
  1433. alert('FC Layers, Illinois:\n'
  1434. + 'Due to changes in the way IDOT is presenting data, the FC highlights represent the MINIMUM road type in WME.'
  1435. + ' Further research will be required to determine proper road type for US / IL / County highways.')
  1436. }
  1437.  
  1438. _fcCallCount += 1;
  1439. _lastPromise = map;
  1440. }
  1441.  
  1442. function onLayerCheckboxChanged(checked) {
  1443. _mapLayer.setVisibility(checked);
  1444. }
  1445.  
  1446. function onLayerVisibilityChanged(evt) {
  1447. _settings.layerVisible = _mapLayer.visibility;
  1448. saveSettingsToStorage();
  1449. if (_mapLayer.visibility) {
  1450. fetchAllFC();
  1451. }
  1452. }
  1453.  
  1454. function onModeChanged(model, modeId, context) {
  1455. if (!modeId || modeId === 1) {
  1456. initUserPanel();
  1457. }
  1458. }
  1459.  
  1460. function showScriptInfoAlert() {
  1461. /* Check version and alert on update */
  1462. if (_alertUpdate && _scriptVersion !== _settings.lastVersion) {
  1463. alert(_scriptVersionChanges);
  1464. }
  1465. }
  1466.  
  1467. function initLayer() {
  1468. var _drawingContext = {
  1469. getZIndex: function (feature) {
  1470. return feature.attributes.zIndex;
  1471. },
  1472. getStrokeWidth: function () { return getLineWidth(); }
  1473. };
  1474. var defaultStyle = new OL.Style({
  1475. strokeColor: '${color}', //'#00aaff',
  1476. strokeDashstyle: "solid",
  1477. strokeOpacity: 1.0,
  1478. strokeWidth: '${strokeWidth}',
  1479. graphicZIndex: '${zIndex}'
  1480. });
  1481.  
  1482. var selectStyle = new OL.Style({
  1483. //strokeOpacity: 1.0,
  1484. strokeColor: '#000000'
  1485. });
  1486.  
  1487. _mapLayer = new OL.Layer.Vector("FC Layer", {
  1488. uniqueName: "__FCLayer",
  1489. displayInLayerSwitcher: false,
  1490. rendererOptions: { zIndexing: true },
  1491. styleMap: new OL.StyleMap({
  1492. 'default': defaultStyle,
  1493. 'select': selectStyle
  1494. })
  1495. });
  1496.  
  1497. _mapLayer.setOpacity(0.5);
  1498.  
  1499. I18n.translations[I18n.locale].layers.name.__FCLayer = "FC Layer";
  1500.  
  1501. _mapLayer.displayInLayerSwitcher = true;
  1502. _mapLayer.events.register('visibilitychanged', null, onLayerVisibilityChanged);
  1503. _mapLayer.setVisibility(_settings.layerVisible);
  1504.  
  1505. W.map.addLayer(_mapLayer);
  1506. _mapLayer.setZIndex(_mapLayerZIndex);
  1507. WazeWrap.Interface.AddLayerCheckbox('Display', 'FC Layer', _settings.layerVisible, onLayerCheckboxChanged);
  1508. // Hack to fix layer zIndex. Some other code is changing it sometimes but I have not been able to figure out why.
  1509. // It may be that the FC layer is added to the map before some Waze code loads the base layers and forces other layers higher. (?)
  1510.  
  1511. var checkLayerZIndex = function () {
  1512. if (_mapLayer.getZIndex() != _mapLayerZIndex) {
  1513. log("ADJUSTED FC LAYER Z-INDEX " + _mapLayerZIndex + ', ' + _mapLayer.getZIndex(), 1);
  1514. _mapLayer.setZIndex(_mapLayerZIndex);
  1515. }
  1516. };
  1517.  
  1518. setInterval(function () { checkLayerZIndex(); }, 200);
  1519.  
  1520. W.map.events.register("moveend", W.map, function (e) {
  1521. fetchAllFC();
  1522. return true;
  1523. }, true);
  1524. }
  1525.  
  1526. function initUserPanel() {
  1527. var $tab = $('<li>').append($('<a>', { 'data-toggle': 'tab', href: '#sidepanel-fc-layer' }).text('FC'));
  1528. var $panel = $('<div>', { class: 'tab-pane', id: 'sidepanel-fc-layer' });
  1529. var $stateSelect = $('<select>', { id: 'fcl-state-select', class: 'form-control disabled', style: 'disabled' }).append($('<option>', { value: 'ALL' }).text('All'));
  1530. // $stateSelect.change(function(evt) {
  1531. // _settings.activeStateAbbr = evt.target.value;
  1532. // saveSettingsToStorage();
  1533. // _mapLayer.removeAllFeatures();
  1534. // fetchAllFC();
  1535. // });
  1536. for (var stateAbbr in _stateSettings) {
  1537. if (stateAbbr !== 'global') {
  1538. $stateSelect.append($('<option>', { value: stateAbbr }).text(reverseStatesHash(stateAbbr)));
  1539. }
  1540. }
  1541.  
  1542. var $hideStreet = $('<div>', { id: 'fcl-hide-street-container', class: 'controls-container' })
  1543. .append($('<input>', { type: 'checkbox', name: 'fcl-hide-street', id: 'fcl-hide-street' }).prop('checked', _settings.hideStreet).click(function () {
  1544. _settings.hideStreet = $(this).is(':checked');
  1545. saveSettingsToStorage();
  1546. _mapLayer.removeAllFeatures();
  1547. fetchAllFC();
  1548. }))
  1549. .append($('<label>', { for: 'fcl-hide-street' }).text('Hide local street highlights'));
  1550.  
  1551. $stateSelect.val(_settings.activeStateAbbr ? _settings.activeStateAbbr : 'ALL');
  1552.  
  1553. $panel.append(
  1554. $('<div>', { class: 'form-group' }).append(
  1555. $('<label>', { class: 'control-label' }).text('Select a state')
  1556. ).append(
  1557. $('<div>', { class: 'controls', id: 'fcl-state-select-container' }).append(
  1558. $('<div>').append($stateSelect)
  1559. )
  1560. ),
  1561. $hideStreet,
  1562. $('<div>', { id: 'fcl-table-container' })
  1563. );
  1564.  
  1565. $panel.append(
  1566. $('<div>', { style: 'margin-top:10px;font-size:10px;color:#999999;' })
  1567. .append($('<div>').text('version ' + _scriptVersion))
  1568. .append(
  1569. $('<div>').append(
  1570. $('<a>', { href: '#' /*, target:'__blank'*/ }).text('Discussion Forum (currently n/a)')
  1571. )
  1572. )
  1573. );
  1574.  
  1575. $('#user-tabs > .nav-tabs').append($tab);
  1576. $('#user-info > .flex-parent > .tab-content').append($panel);
  1577. $('#fcl-state-select').change(function () {
  1578. _settings.activeStateAbbr = this.value;
  1579. saveSettingsToStorage();
  1580. fetchAllFC();
  1581. });
  1582. }
  1583.  
  1584. function addLoadingIndicator() {
  1585. $('.loading-indicator').after($('<div class="loading-indicator" style="margin-right:10px" id="fc-loading-indicator">'));
  1586. }
  1587.  
  1588. function initGui() {
  1589. addLoadingIndicator();
  1590. initLayer();
  1591. initUserPanel();
  1592. showScriptInfoAlert();
  1593. }
  1594.  
  1595. function processText(text) {
  1596. return new Promise(function (resolve, reject) {
  1597. var newText = text.replace(/(e)/, 'E');
  1598. resolve(newText);
  1599. });
  1600. }
  1601.  
  1602. function init() {
  1603. if (_debugLevel > 0 && Promise.config) {
  1604. Promise.config({
  1605. warnings: true,
  1606. longStackTraces: true,
  1607. cancellation: true,
  1608. monitoring: false
  1609. });
  1610. } else {
  1611. Promise.config({
  1612. warnings: false,
  1613. longStackTraces: false,
  1614. cancellation: true,
  1615. monitoring: false
  1616. });
  1617. }
  1618.  
  1619. var u = W.loginManager.user;
  1620. _uid = u.id;
  1621. _r = u.rank;
  1622. _isAM = u.isAreaManager;
  1623. loadSettingsFromStorage();
  1624. String.prototype.replaceAll = function (search, replacement) {
  1625. var target = this;
  1626. return target.replace(new RegExp(search, 'g'), replacement);
  1627. };
  1628. initGui();
  1629. W.app.modeController.model.bind('change:mode', onModeChanged);
  1630. W.prefs.on("change:isImperial", function () { initUserPanel(); loadSettingsFromStorage(); });
  1631. fetchAllFC();
  1632. log('Initialized.', 0);
  1633. }
  1634.  
  1635. function bootstrap() {
  1636. if (W && W.loginManager &&
  1637. W.loginManager.events &&
  1638. W.loginManager.events.register &&
  1639. W.model && W.model.states && W.model.states.additionalInfo &&
  1640. W.map && W.loginManager.user &&
  1641. WazeWrap.Ready) {
  1642. log('Initializing...', 0);
  1643.  
  1644. init();
  1645. } else {
  1646. log('Bootstrap failed. Trying again...', 0);
  1647. unsafeWindow.setTimeout(function () {
  1648. bootstrap();
  1649. }, 1000);
  1650. }
  1651. }
  1652.  
  1653. log('Bootstrap...', 0);
  1654. bootstrap();
  1655. })();