WME DOT Cameras

Overlay DOT Cameras on the WME Map Object

当前为 2020-07-29 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name WME DOT Cameras
  3. // @namespace https://greasyfork.org/en/users/668704-phuz
  4. // @require https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
  5. // @version 1.06
  6. // @description Overlay DOT Cameras on the WME Map Object
  7. // @author phuz
  8. // @include /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor\/?.*$/
  9. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
  10. // @grant GM_xmlhttpRequest
  11. // @grant GM_info
  12. // @grant GM_fetch
  13. // @grant GM_addStyle
  14. // @require https://cdn.jsdelivr.net/npm/hls.js@latest
  15. // @require https://unpkg.com/video.js/dist/video.js
  16. // @require https://unpkg.com/@videojs/http-streaming/dist/videojs-http-streaming.js
  17. // @connect jsdelivr.net
  18. // @connect 511pa.com
  19. // @connect deldot.gov
  20. // @connect 511ny.org
  21. // @connect 511nj.org
  22. // @connect maryland.gov
  23. // @connect 511virginia.org
  24. // @connect newengland511.org
  25. /* global OpenLayers */
  26. /* global W */
  27. /* global WazeWrap */
  28. /* global $ */
  29. /* global I18n */
  30. /* global _ */
  31. // ==/UserScript==
  32.  
  33. let PALayer;
  34. let DELayer;
  35. let NELayer;
  36. let NYLayer;
  37. let NJLayer;
  38. let MDLayer;
  39. let VALayer;
  40. var settings;
  41. var video;
  42. var player;
  43. var hls;
  44. const camIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAAGXcA1uAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpBRDNGNTkwRTYzQThFMzExQTc4MDhDNjAwODdEMzdEQSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2OUI0RUEyN0IwRjcxMUUzOERFM0E1OTJCRUY3NTFBOCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2OUI0RUEyNkIwRjcxMUUzOERFM0E1OTJCRUY3NTFBOCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjZGOEJBMzExNkZCMEUzMTFCOEY5QTU3QUQxM0M2MjI5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkFEM0Y1OTBFNjNBOEUzMTFBNzgwOEM2MDA4N0QzN0RBIi8+IDwvcmRmOkRlc2NyaXB0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';
  45. const warning = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA/ppVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ1dWlkOjVEMjA4OTI0OTNCRkRCMTE5MTRBODU5MEQzMTUwOEM4IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjk4MDFDMjUwNzIzRDExRTNBQTczRjkyOTZEQ0IyOTY0IiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjk4MDFDMjRGNzIzRDExRTNBQTczRjkyOTZEQ0IyOTY0IiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIElsbHVzdHJhdG9yIENDIChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ1dWlkOmFiMzczNzVkLWIwYTYtNDRjNC04OTE4LWU4M2ZiOTRhOGY4NSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpjMjUyYWZlMC1mMjU0LWY5NDMtOGZiZi0wMTc3Mzc1ZWEzYzYiLz4gPGRjOnRpdGxlPiA8cmRmOkFsdD4gPHJkZjpsaSB4bWw6bGFuZz0ieC1kZWZhdWx0Ij5JbmNpZGVudHNfb3V0bGluZWQ8L3JkZjpsaT4gPC9yZGY6QWx0PiA8L2RjOnRpdGxlPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pmcc3z4AAASdSURBVHja7FdLaFxVGP7OPfc1M5lMJ5M0Gk0nNdE+sogPLNG2KNaFUksqlkAjSGtcCBJUWgouhErAUOhCwb2uXJQupCtF0I102SrEUsFNkRaxJJ3MTGbu+/j/J2lnKp04HdNkY+AnZ875/u9853/ce65QSmEz/wxs8t//AjZdgDkytL1j5whIaRKgvuERCIH9UDjHpsedRqATJwE8Yimcn5LuVv79deztEQJPU0Nf35AILCZq7lXX3jqds8DGY5574Cmgk6OS4PCoJaamcvSjO9HGY57jtQcqwFPot1V85lhByPHptzBw7jttz9H4eK8hnSQ+4xPmfjhlz5YtbQHprChH6vRrTuXQqddfgP3+HGSuANnVDYw9ix3XL+G3X68UfgkduFJ8L9Y7AvUYL+7MipMndig4eQdKNOqXx07exomdCoxh7LqmIFRwbYHP3t1uYHevgXq9CgRNre/X9ByvMYax7LN+EVA4/XKfMTbRJ3GzYiKs+lCh31gOA4Tlul5jDGPZZ10ERAp7C7aYmX7YgvIl6p4Fv+IjCcJGfZAAvxroNcYwln3Y978KkLVEfXK0z0yPmAbKNYEglAjKAZ06bIpAhKASIvBXMIxlH/Zljo4EcBUvRsl7e7vkgYMZC/Ua554E0An98j8iEFAEyh6CwNQYxrIP+zKH6ERATanhHtP46M2sgxydurRMdeeRAM+Ed8tD4gcNAV6g53zf1BjGsg/7Mgdz3ZcAeqbTo158fiRtP/SMsPAnEYYU3sAz6L+EV/IQeY0ijFnAko+I1lYwhvZhX+ZgLuZsW0BVqalRUx6ckA7lVMH3WMCqhSSEU+A3UhBTOgIWEBp3cOzDvszBXMzZlgCiHcwL8ekbho1UYIAKHoqinfirFlIaKAJJEDfVQKTnYlq7jWMf9mUO5mJO5l5TgNKXDDW3H/bAk7GFcqD0hnGTJTGFWatqdiRRVIS8dheWjDmYizmZW60lgACHt0EemVAOkdFJknubYbtY+nn+jl+ZxobltsQzF3MyN+9xV7cNF4f0YahVBkKlLp6UmeI+Kp4qvX5afjEkCjLloO/QK/rnXxe+pU6gqBiiZUt30Vl/UiHOxsvXLCGeJ+4b4nYEeHBLqVMHLKu4zzWROAmodmC2MEP4SA32Izu6W1u62K/nWuGZizmZm/fgvUTzlWw5US8Nm3JmMuMgQzOlVj2jn3pUSl0mRmY/RveecT2X2TWMq++8Te0QQtj39uSSzdKuk5aD+Uoy80cUX8gY4geTaiRPX2ezk92WMZaTWIiTNV9jyo8gM1m4xcZt2t1WRLrgIi6XIdzW10x6gGNMSkwKyzi7EM/S3pdlKpv7YCJvHf/wURvKVrApXKm1LC1h+SU4jgV7eBddk+qof/Mloks/IpNPI+W29nU5fY7CU90GbgRq8Eo9LplpQ4w/QZeaJBVhgaIr2rnKOGlUzn8BZ/7iynXg6mUYhfRqoP/lzU7p7aUs8Z7pJTEuHisOHe1z8FUPvUljhfY+lVkl9VdSXVrp5QyxUWjR5pe2FBCLVC43fRwTj1Mb0kVypBbrLtqQb3XqYkGZhCPw+98CDACt/EZVMWT0ogAAAABJRU5ErkJggg==';
  46. const PAURL = 'https://www.511pa.com/wsvc/gmap.asmx/buildCamerasJSONjs';
  47. const DEURL = 'https://tmc.deldot.gov/json/videocamera.json';
  48. const NYAPI = 'ZGE3YzZkNzBmMWY4NGEyZWJhOWFhODBmYTE2NmI2ZTg=';
  49. const NYURL = `https://511ny.org/api/getcameras?key=${atob(NYAPI)}&format=json`;
  50. const NJURL = 'https://511nj.org/api/client/camera/GetCameraDataByTourId?tourid=&rnd=202007201015';
  51. const MDURL = 'https://chartexp1.sha.maryland.gov//CHARTExportClientService/getCameraMapDataJSON.do';
  52. const VAURL = "https://www.511virginia.org/data/geojson/icons.cameras.geojson";
  53. const NEURL = 'http://newengland511.org/Traffic/GetCameras';
  54.  
  55. (function() {
  56. 'use strict';
  57. //Bootstrap
  58. function bootstrap(tries = 1) {
  59. if (W && W.loginManager && W.map && W.loginManager.user && W.model && W.model.states && W.model.states.getObjectArray().length && WazeWrap && WazeWrap.Ready) {
  60. console.log("WME DOT Cameras Loaded!");
  61. init();
  62. installIcon();
  63. } else if (tries < 1000) {
  64. setTimeout(function () {bootstrap(++tries);}, 200);
  65. }
  66. }
  67. //Build the Tab and Settings Division
  68. function init()
  69. {
  70. var $section = $("<div>");
  71. $section.html([
  72. '<div id="chkEnables">',
  73. '<table border=1 style="text-align:center;width:100%;padding:10px;">',
  74. '<tr><td width=50 valign=middle><img src="' + warning + '" height=16 width=16></td><td style="text-align:center">Warning: WME Toolbox has caused interference with methods this script uses to play video feeds. Until the Toolbox issues are resolved, it needs to remain disabled in order to run this script.</td><td width=50><img src="' + warning + '" height=16 width=16></td></tr>',
  75. '<tr><td colspan=2 style="text-align:center"><b>Enable</b></td><td style="text-align"><b>State</b></td></tr>',
  76. '<tr><td colspan=2 align=center><input type="checkbox" id="chkDECamEnabled" class="wmedotSettingsCheckbox"></td><td align=center>DE</td></tr>',
  77. '<tr><td colspan=2 align=center><input type="checkbox" id="chkMDCamEnabled" class="wmedotSettingsCheckbox"></td><td align=center>MD</td></tr>',
  78. '<tr><td colspan=2 align=center><input type="checkbox" id="chkNYCamEnabled" class="wmedotSettingsCheckbox"></td><td align=center>NY</td></tr>',
  79. '<tr><td colspan=2 align=center><input type="checkbox" id="chkNECamEnabled" class="wmedotSettingsCheckbox"></td><td align=center>New England</td></tr>',
  80. '<tr><td colspan=2 align=center><input type="checkbox" id="chkNJCamEnabled" class="wmedotSettingsCheckbox"></td><td align=center>NJ</td></tr>',
  81. '<tr><td colspan=2 align=center><input type="checkbox" id="chkPACamEnabled" class="wmedotSettingsCheckbox"></td><td align=center>PA</td></tr>',
  82. '<tr><td colspan=2 align=center><input type="checkbox" id="chkVACamEnabled" class="wmedotSettingsCheckbox"></td><td align=center>VA</td></tr>',
  83. '</table>',
  84. 'Click <a href="https://www.waze.com/forum/viewtopic.php?f=819&t=145570&start=2270#p2078310">here</a> to see the forum post regarding the conflict with the current version of WME Toolbox',
  85. '</div></div>'
  86. ].join(' '));
  87. new WazeWrap.Interface.Tab('DOT Cameras', $section.html(), initializeSettings);
  88. }
  89. //Build the State Layers
  90. function buildDOTCamLayers(state) {
  91. eval(state.substring(0,2) + 'Layer = new OpenLayers.Layer.Markers(' + state.substring(0,2) + 'Layer)');
  92. eval('W.map.addLayer(' + state.substring(0,2) + 'Layer)');
  93. }
  94. function getCamFeed(url,type,callback) {
  95. GM_xmlhttpRequest({
  96. method: "GET",
  97. url: url,
  98. onload: function(response) {
  99. var result = response.responseText;
  100. callback(result);
  101. }
  102. });
  103. }
  104. //Get the PA Camera JSON Feed (We can't used the canned getCamFeed function because of the extra legwork we have to do with the PA feed)
  105. function getPA() {
  106. $.ajax ({
  107. type: 'GET',
  108. url: PAURL,
  109. dataType: 'text',
  110. success: function (results) {
  111. let result = results.toString().match(/camera_data = ([\s\S]*)/);
  112. var resultObj = JSON.parse(result[1]).cams;
  113. var i=0;
  114. while (i<resultObj.length) {
  115. drawCameras("PA",2,resultObj[i].start_lng,resultObj[i].start_lat,resultObj[i].md5,resultObj[i].title);
  116. i++;
  117. }
  118. }
  119. });
  120. }
  121. //Get the DE Camera JSON Feed
  122. function getDE() {
  123. getCamFeed(DEURL,"json", function(result) {
  124. var resultObj = JSON.parse(result).videoCameras;
  125. var i=0;
  126. while (i<resultObj.length) {
  127. drawCameras("DE",0,resultObj[i].lon,resultObj[i].lat,resultObj[i].urls.m3u8s,resultObj[i].title + " (" + resultObj[i].county + ")",550,300);
  128. i++;
  129. }
  130. });
  131. }
  132. //Get the VA Camera JSON Feed
  133. function getVA() {
  134. getCamFeed(VAURL,"json", function(result) {
  135. var resultObj = JSON.parse(result).features;
  136. var i=0;
  137. while (i<resultObj.length) {
  138. drawCameras("VA",0,resultObj[i].geometry.coordinates[0],resultObj[i].geometry.coordinates[1],resultObj[i].properties.https_url,resultObj[i].properties.description,550,300);
  139. i++;
  140. }
  141. });
  142. }
  143. //Get the NY Camera JSON Feed
  144. function getNY() {
  145. getCamFeed(NYURL,"json", function(result) {
  146. var resultObj = JSON.parse(result);
  147. var i=0;
  148. while (i<resultObj.length) {
  149. if (resultObj[i].VideoUrl != null) {
  150. drawCameras("NY",0,resultObj[i].Longitude,resultObj[i].Latitude,resultObj[i].VideoUrl,resultObj[i].Name,550,300);
  151. }
  152. i++;
  153. }
  154. });
  155. }
  156. //Get the NJ Camera JSON Feed
  157. function getNJ() {
  158. getCamFeed(NJURL,"json", function(result) {
  159. var resultObj = JSON.parse(result).Data.CameraData;
  160. var i=0;
  161. while (i<resultObj.length) {
  162. drawCameras("NJ",0,resultObj[i].longitude,resultObj[i].latitude,resultObj[i].CameraMainDetail[0].URL,resultObj[i].name,480,360);
  163. i++;
  164. }
  165. });
  166. }
  167. function getMD() {
  168. getCamFeed(MDURL,"json", function(result){
  169. var resultObj = JSON.parse(result).data;
  170. var i=0;
  171. while (i<resultObj.length){
  172. drawCameras("MD",0,resultObj[i].lon,resultObj[i].lat,'https://' + resultObj[i].cctvIp + '/rtplive/' + resultObj[i].id + '/playlist.m3u8',resultObj[i].description,480,360);
  173. i++;
  174. }
  175. });
  176. }
  177. function getNE() {
  178. getCamFeed(NEURL,"json", function(result){
  179. var resultObj = JSON.parse(result);
  180. var i=0;
  181. while (i<resultObj.length){
  182. drawCameras("NE",1,resultObj[i].Longitude,resultObj[i].Latitude,resultObj[i].ImageUrl,resultObj[i].Name);
  183. i++;
  184. }
  185. });
  186. }
  187.  
  188. //Generate the Camera markers
  189. function drawCameras(state,camType,x,y,url,title,width,height) {
  190. var size = new OpenLayers.Size(20,20);
  191. var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
  192. var icon = new OpenLayers.Icon(camIcon,size);
  193. var epsg4326 = new OpenLayers.Projection("EPSG:4326"); //WGS 1984 projection
  194. var projectTo = W.map.getProjectionObject(); //The map projection (Spherical Mercator)
  195. var lonLat = new OpenLayers.LonLat(x,y).transform(epsg4326,projectTo);
  196. var newMarker = new OpenLayers.Marker(lonLat,icon);
  197. newMarker.title = title;
  198. newMarker.url = url;
  199. newMarker.width = width;
  200. newMarker.height = height;
  201. newMarker.state = state;
  202. newMarker.camType = camType;
  203. newMarker.events.register('click',newMarker,popupCam);
  204. eval(state + 'Layer.addMarker(newMarker)');
  205. }
  206. //Generate the Camera Popup
  207. function popupCam(evt) {
  208. //Check to see if WME Toolbox is running, and if it is, go no further (hopefully temporary!)
  209. var i=0;
  210. while(i<document.getElementsByTagName('script').length) {
  211. if(document.getElementsByTagName('script')[i].src == "chrome-extension://ihebciailciabdiknfomleeccodkdejn/scripts/WME_Toolbox.prod.min.js") {
  212. alert("WME DOT Cameras cannot run if Toolbox is enabled, due to current issues with the Toolbox extension. Please disable the Toolbox extension in order to use this script until the issue is resolved.");
  213. return;
  214. }
  215. i++;
  216. }
  217. $("#gmPopupContainer").remove ();
  218. $("#gmPopupContainer").hide ();
  219. var popupHTML = [];
  220. popupHTML[0] = (['<div id="gmPopupContainer">' +
  221. '<center><h3>' + this.title + '</h3>' +
  222. '<div id="videoDiv">' +
  223. '<video id="hlsVideo" width=' + this.width + ' height=' + this.height + ' controls autoplay></video>' +
  224. '</div>' +
  225. '<form><button id="gmCloseDlgBtn" type="button">Close</button></form>' +
  226. '</div>'
  227. ]);
  228. popupHTML[1] = (['<div id="gmPopupContainer">' +
  229. '<center><h3>' + this.title + '</h3>' +
  230. '<img src="' + this.url + '" width=320 height=240 id="staticimage">' +
  231. '<form><button id="gmCloseDlgBtn" type="button">Close</button></form>' +
  232. '</div>'
  233. ]);
  234. popupHTML[2] = (['<div id="gmPopupContainer">' +
  235. '<center><h3>' + this.title + '</h3><br>' +
  236. '<iframe class="video" id="fp_embed_player" src="https://www.511pa.com/flowplayeri.aspx?CAMID=' + this.url + '"&autoplay=1 style="background: #FFFFFF;margin: 5px 20px;" frameborder=0 width=320 height=240 scrolling=no allowfullscreen=allowfullscreen></iframe>' +
  237. '<br><form><button id="gmCloseDlgBtn" type="button">Close</button>' +
  238. '</form></div>'
  239. ]);
  240. var currentCamURL = this.url;
  241. switch(this.camType) {
  242. case 0:
  243. $("body").append(popupHTML[0]);
  244. setTimeout(function () {
  245. video = document.getElementById('hlsVideo');
  246. var videoSrc = currentCamURL;
  247. if (Hls.isSupported()) {
  248. hls = new Hls();
  249. hls.loadSource(videoSrc);
  250. hls.attachMedia(video);
  251. hls.on(Hls.Events.MANIFEST_PARSED, function() {
  252. video.play();
  253. });
  254. }
  255. },1000);
  256. break;
  257. case 1:
  258. $("body").append(popupHTML[1]);
  259. var staticUpdateID = setInterval(function() {
  260. var camImage = document.getElementById('staticimage');
  261. camImage.src = currentCamURL + '?rand=' + Math.random();
  262. }, 5000);
  263. break;
  264. case 2:
  265. $("body").append(popupHTML[2]);
  266. }
  267. //Position the modal based on the position of the click event
  268. if (evt.pageX > document.getElementById("gmPopupContainer").clientWidth + 50) {$("#gmPopupContainer").css({left: evt.pageX - document.getElementById("gmPopupContainer").clientWidth - 10});}
  269. else { $("#gmPopupContainer").css({left: evt.pageX + 10}); }
  270. if (evt.pageY > document.getElementById("gmPopupContainer").clientHeight + 50) {$("#gmPopupContainer").css({top: evt.pageY - (document.getElementById("gmPopupContainer").clientHeight) - 10});}
  271. else { $("#gmPopupContainer").css({top: evt.pageY + 10}); }
  272. //Add listener for popup's "Close" button
  273. $("#gmCloseDlgBtn").click ( function () {
  274. if (hls) {
  275. hls.destroy();
  276. }
  277. clearInterval(staticUpdateID);
  278. $("#gmPopupContainer").remove ();
  279. $("#gmPopupContainer").hide ();
  280. });
  281. fetch(this.url)
  282. .then(response => {
  283. if (!response.ok) {
  284. //Good feed
  285. $('#videoDiv').empty();
  286. document.getElementById('videoDiv').innerHTML = "<br>Sorry, this feed is currently offline.";
  287. } else {
  288. //Bad Feed
  289. }
  290. });
  291. }
  292. function initializeSettings()
  293. {
  294. loadSettings();
  295. setChecked('chkPACamEnabled', settings.PACamEnabled);
  296. setChecked('chkDECamEnabled', settings.DECamEnabled);
  297. setChecked('chkNECamEnabled', settings.NECamEnabled);
  298. setChecked('chkNYCamEnabled', settings.NYCamEnabled);
  299. setChecked('chkNJCamEnabled', settings.NJCamEnabled);
  300. setChecked('chkMDCamEnabled', settings.MDCamEnabled);
  301. setChecked('chkVACamEnabled', settings.VACamEnabled);
  302.  
  303. //Add Handler for Checkbox Setting Changes
  304. $('.wmedotSettingsCheckbox').change(function() {
  305. var settingName = $(this)[0].id.substr(3);
  306. settings[settingName] = this.checked;
  307. saveSettings();
  308. if(this.checked) {
  309. buildDOTCamLayers(settingName.substring(0,2));
  310. eval("get" + settingName.substring(0,2) + "()");
  311. }
  312. else
  313. {
  314. eval(settingName.substring(0,2) + "Layer.destroy()");
  315. }
  316. });
  317. if (document.getElementById('chkPACamEnabled').checked) { buildDOTCamLayers("PA"); getPA(); }
  318. if (document.getElementById('chkDECamEnabled').checked) { buildDOTCamLayers("DE"); getDE(); }
  319. if (document.getElementById('chkNECamEnabled').checked) { buildDOTCamLayers("NE"); getNE(); }
  320. if (document.getElementById('chkNYCamEnabled').checked) { buildDOTCamLayers("NY"); getNY(); }
  321. if (document.getElementById('chkNJCamEnabled').checked) { buildDOTCamLayers("NJ"); getNJ(); }
  322. if (document.getElementById('chkMDCamEnabled').checked) { buildDOTCamLayers("MD"); getMD(); }
  323. if (document.getElementById('chkVACamEnabled').checked) { buildDOTCamLayers("VA"); getVA(); }
  324. }
  325. //Set Checkbox from Settings
  326. function setChecked(checkboxId, checked) {
  327. $('#' + checkboxId).prop('checked', checked);
  328. }
  329. //Load Saved Settings
  330. function loadSettings() {
  331. var loadedSettings = $.parseJSON(localStorage.getItem("Camera_Settings"));
  332. var defaultSettings = {
  333. Enabled: false,
  334. };
  335. settings = loadedSettings ? loadedSettings : defaultSettings;
  336. for (var prop in defaultSettings) {
  337. if (!settings.hasOwnProperty(prop)) {
  338. settings[prop] = defaultSettings[prop];
  339. }
  340. }
  341. }
  342. //Save Tab Settings
  343. function saveSettings() {
  344. if (localStorage) {
  345. var localsettings = {
  346. PACamEnabled: settings.PACamEnabled,
  347. DECamEnabled: settings.DECamEnabled,
  348. NECamEnabled: settings.NECamEnabled,
  349. NYCamEnabled: settings.NYCamEnabled,
  350. NJCamEnabled: settings.NJCamEnabled,
  351. MDCamEnabled: settings.MDCamEnabled,
  352. VACamEnabled: settings.VACamEnabled,
  353. };
  354. localStorage.setItem("Camera_Settings", JSON.stringify(localsettings));
  355. }
  356. }
  357. //Add the Icon Class to OpenLayers
  358. function installIcon() {
  359. console.log('Installing OpenLayers.Icon');
  360. OpenLayers.Icon = OpenLayers.Class({
  361. url: null,
  362. size: null,
  363. offset: null,
  364. calculateOffset: null,
  365. imageDiv: null,
  366. px: null,
  367. initialize: function(a,b,c,d){
  368. this.url=a;
  369. this.size=b||{w: 20,h: 20};
  370. this.offset=c||{x: -(this.size.w/2),y: -(this.size.h/2)};
  371. this.calculateOffset=d;
  372. a=OpenLayers.Util.createUniqueID("OL_Icon_");
  373. let div = this.imageDiv=OpenLayers.Util.createAlphaImageDiv(a);
  374. $(div.firstChild).removeClass('olAlphaImg'); // LEAVE THIS LINE TO PREVENT WME-HARDHATS SCRIPT FROM TURNING ALL ICONS INTO HARDHAT WAZERS --MAPOMATIC
  375. },
  376. destroy: function(){ this.erase();OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);this.imageDiv.innerHTML="";this.imageDiv=null; },
  377. clone: function(){ return new OpenLayers.Icon(this.url,this.size,this.offset,this.calculateOffset); },
  378. setSize: function(a){ null!==a&&(this.size=a); this.draw(); },
  379. setUrl: function(a){ null!==a&&(this.url=a); this.draw(); },
  380. draw: function(a){
  381. OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,this.size,this.url,"absolute");
  382. this.moveTo(a);
  383. return this.imageDiv;
  384. },
  385. erase: function(){ null!==this.imageDiv&&null!==this.imageDiv.parentNode&&OpenLayers.Element.remove(this.imageDiv); },
  386. setOpacity: function(a){ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,null,null,null,null,null,a); },
  387. moveTo: function(a){
  388. null!==a&&(this.px=a);
  389. null!==this.imageDiv&&(null===this.px?this.display(!1): (
  390. this.calculateOffset&&(this.offset=this.calculateOffset(this.size)),
  391. OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,{x: this.px.x+this.offset.x,y: this.px.y+this.offset.y})
  392. ));
  393. },
  394. display: function(a){ this.imageDiv.style.display=a?"": "none"; },
  395. isDrawn: function(){ return this.imageDiv&&this.imageDiv.parentNode&&11!=this.imageDiv.parentNode.nodeType; },
  396. CLASS_NAME: "OpenLayers.Icon"
  397. });
  398. }
  399. //--- CSS styles make it work...
  400. GM_addStyle (" \
  401. #gmPopupContainer { \
  402. position: fixed; \
  403. top: 10%; \
  404. left: 20%; \
  405. padding: 1em; \
  406. background: lightgray; \
  407. border: 3px double black; \
  408. border-radius: 1ex; \
  409. z-index: 777; \
  410. display: flex; \
  411. } \
  412. #gmPopupContainer button{ \
  413. cursor: pointer; \
  414. margin: 1em 1em 0; \
  415. border: 1px outset buttonface; \
  416. } \
  417. ");
  418. bootstrap();
  419. })();