Modify Traces

Modify the Waze & User trace displayed by URs

  1. // ==UserScript==
  2. // @name Modify Traces
  3. // @namespace https://gf.qytechs.cn/users/30701-justins83-waze
  4. // @version 2018.11.07.01
  5. // @description Modify the Waze & User trace displayed by URs
  6. // @author JustinS83
  7. // @include https://www.waze.com/editor*
  8. // @include https://www.waze.com/*/editor*
  9. // @include https://beta.waze.com*
  10. // @exclude https://www.waze.com/*user/editor*
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. /* global W */
  15. /* global OL */
  16. /* ecmaVersion 2017 */
  17. /* global $ */
  18. /* global _ */
  19. /* global WazeWrap */
  20. /* global require */
  21. /* eslint curly: ["warn", "multi-or-nest"] */
  22.  
  23. (function() {
  24. 'use strict';
  25.  
  26. var URMO;
  27. var recoloredArrow = "";
  28. var recoloredUserArrow = "";
  29. var img = new Image();
  30. var userArrow = new Image();
  31. var mIcon;
  32.  
  33. function bootstrap(tries = 1) {
  34. if (W && W.map &&
  35. W.model && W.loginManager.user &&
  36. $)
  37. init();
  38. else if (tries < 1000)
  39. setTimeout(function () {bootstrap(tries++);}, 200);
  40. }
  41.  
  42. bootstrap();
  43.  
  44. function modifyRules(){
  45. getTraceLayer().then(val => {
  46. //In theory these are always the same index - but better to search and be sure we get the right ones
  47. let sugRouteArrowIndex = val.styleMap.styles.default.rules.findIndex(function(e){ return e.filter.value == "suggestedRouteArrow";});
  48. let sugRouteIndex = val.styleMap.styles.default.rules.findIndex(function(e){ return e.filter.value == "suggestedRoute";});
  49. let userRouteArrowIndex = val.styleMap.styles.default.rules.findIndex(function(e){ return e.filter.value == "driveArrow";});
  50. let userRouteIndex = val.styleMap.styles.default.rules.findIndex(function(e){ return e.filter.value == "drive";});
  51.  
  52. //Waze suggested route
  53. //default is 5
  54. val.styleMap.styles.default.rules[sugRouteArrowIndex].symbolizer.graphicHeight = 8;
  55. //default is 9
  56. val.styleMap.styles.default.rules[sugRouteArrowIndex].symbolizer.graphicWidth = 12;
  57.  
  58. //User driven route
  59. //default is 5
  60. val.styleMap.styles.default.rules[userRouteArrowIndex].symbolizer.graphicHeight = 8;
  61. //default is 9
  62. val.styleMap.styles.default.rules[userRouteArrowIndex].symbolizer.graphicWidth = 12;
  63. //This would change the route color from dark purple
  64. //val.styleMap.styles.default.rules[sugRouteIndex].symbolizer.strokeColor = "#c77aff";
  65.  
  66. getModifiedArrow().then(result => {
  67. val.styleMap.styles.default.rules[sugRouteArrowIndex].symbolizer.externalGraphic = recoloredArrow;
  68. val.redraw();
  69. });
  70.  
  71. getModifiedUserArrow().then(result => {
  72. val.styleMap.styles.default.rules[userRouteArrowIndex].symbolizer.externalGraphic = recoloredUserArrow;
  73. val.redraw();
  74. });
  75.  
  76. val.redraw();
  77. URMO.disconnect(); //We only need the MO to fire once - once the rule is set it persists on the layer. The layer isn't created until the first time a user clicks on a UR, though.
  78. });
  79.  
  80. }
  81.  
  82. function getTraceLayer(tries = 1) { //Need to use a promise to get the layer - if we do not, we have to fudge some delay after clicking to wait until the layer is created and everything set up before we go through our changes
  83. return new Promise((resolve, reject) => {
  84. if (W.map.getLayersByName("problemMoreInfo").length > 0)
  85. resolve(W.map.getLayersByName("problemMoreInfo")[0]);
  86. else {
  87. if(tries <= 10)
  88. setTimeout(() => resolve(getTraceLayer(tries++)), 100);
  89. }
  90. });
  91. }
  92.  
  93. function getModifiedArrow(tries = 1){
  94. return new Promise((resolve, reject) =>{
  95. if(recoloredArrow === ""){
  96. if(tries <= 50)
  97. setTimeout(() => resolve(getModifiedArrow(tries++)), 100);
  98. }
  99. else
  100. resolve(recoloredArrow);
  101. });
  102. }
  103.  
  104. function getModifiedUserArrow(tries = 1){
  105. return new Promise((resolve, reject) =>{
  106. if(recoloredUserArrow === ""){
  107. if(tries <= 50)
  108. setTimeout(() => resolve(getModifiedUserArrow(tries++)), 100);
  109. }
  110. else
  111. resolve(recoloredUserArrow);
  112. });
  113. }
  114.  
  115. function URLayerPopulated(mutations){
  116. mutations.forEach(function(mutation) {
  117. for (var i = 0; i < mutation.addedNodes.length; i++) {
  118. var addedNode = mutation.addedNodes[i];
  119. if (addedNode.nodeType === Node.ELEMENT_NODE && $(addedNode).hasClass('mapUpdateRequest'))
  120. modifyRules();
  121. }
  122. });
  123. }
  124.  
  125. function init(){
  126. img.crossOrigin = "anonymous";
  127. img.onload = recolorArrow;
  128. img.src = "https://editor-assets.waze.com/production/img/one-way-routed9aa340910f8fc7a0fd2285fa0aab968.png";
  129.  
  130. userArrow.crossOrigin = "anonymous";
  131. userArrow.onload = recolorUserArrow;
  132. userArrow.src = "https://editor-assets.waze.com/production/img/one-way-drivee7f57df07fa6d5f61eee9b71ae5e18b1.png";
  133.  
  134. URMO = new MutationObserver(URLayerPopulated);
  135. URMO.observe($('#panel-container')[0], {childList : true, subtree: true});
  136. }
  137.  
  138. //changes the purple Waze drive arrows to white for more contrast.
  139. function recolorArrow() {
  140. let canvas = document.createElement('canvas');
  141. let ctx = canvas.getContext("2d");
  142. ctx.drawImage(img, 0, 0);
  143. let imgData = ctx.getImageData(0, 0, 9, 5);
  144. let data = imgData.data;
  145.  
  146. for (var i = 0; i < data.length; i += 4) {
  147. let red = data[i + 0];
  148. let green = data[i + 1];
  149. let blue = data[i + 2];
  150. let alpha = data[i + 3];
  151.  
  152. // skip transparent/semiTransparent pixels
  153. if (alpha < 10)
  154. continue;
  155.  
  156. let hsl = rgbToHsl(red, green, blue);
  157. let hue = hsl.h * 360;
  158.  
  159. // change purple pixels to the new color
  160. if (hue > 260 && hue < 270) {
  161. var newRgb = hslToRgb((hue - 200)/360, hsl.s, 100);//hsl.l); //Setting l to 100 forces it to white
  162. data[i + 0] = newRgb.r;
  163. data[i + 1] = newRgb.g;
  164. data[i + 2] = newRgb.b;
  165. //data[i + 3] = 255;
  166. }
  167. }
  168. let mycanvas = document.createElement('canvas');
  169. $(mycanvas).attr('width', 9);
  170. $(mycanvas).attr('height', 5);
  171. let newctx = mycanvas.getContext('2d');
  172. newctx.putImageData(imgData,0,0);
  173. recoloredArrow = mycanvas.toDataURL();
  174. }
  175.  
  176. function recolorUserArrow() {
  177. let canvas = document.createElement('canvas');
  178. let ctx = canvas.getContext("2d");
  179. ctx.drawImage(userArrow, 0, 0);
  180. let imgData = ctx.getImageData(0, 0, 9, 5);
  181. let data = imgData.data;
  182.  
  183. for (var i = 0; i < data.length; i += 4) {
  184. let red = data[i + 0];
  185. let green = data[i + 1];
  186. let blue = data[i + 2];
  187. let alpha = data[i + 3];
  188.  
  189. // skip transparent/semiTransparent pixels
  190. if (alpha < 10)
  191. continue;
  192.  
  193. let hsl = rgbToHsl(red, green, blue);
  194. let hue = hsl.h * 360;
  195.  
  196. // change green pixels to the new color
  197. if (hue > 157 && hue < 160) {
  198. var newRgb = hslToRgb((hue - 157)/360, .037, .106);//hsl.l);
  199. data[i + 0] = newRgb.r;
  200. data[i + 1] = newRgb.g;
  201. data[i + 2] = newRgb.b;
  202. }
  203. }
  204. let mycanvas = document.createElement('canvas');
  205. $(mycanvas).attr('width', 9);
  206. $(mycanvas).attr('height', 5);
  207. let newctx = mycanvas.getContext('2d');
  208. newctx.putImageData(imgData,0,0);
  209. recoloredUserArrow = mycanvas.toDataURL();
  210. }
  211.  
  212. function rgbToHsl(r, g, b) {
  213. r /= 255;
  214. g /= 255;
  215. b /= 255;
  216. let max = Math.max(r, g, b),
  217. min = Math.min(r, g, b);
  218. let h, s, l = (max + min) / 2;
  219.  
  220. if (max == min)
  221. h = s = 0; // achromatic
  222. else {
  223. let d = max - min;
  224. s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
  225. switch (max) {
  226. case r:
  227. h = (g - b) / d + (g < b ? 6 : 0);
  228. break;
  229. case g:
  230. h = (b - r) / d + 2;
  231. break;
  232. case b:
  233. h = (r - g) / d + 4;
  234. break;
  235. }
  236. h /= 6;
  237. }
  238.  
  239. return ({
  240. h: h,
  241. s: s,
  242. l: l,
  243. });
  244. }
  245.  
  246. function hue2rgb(p, q, t) {
  247. if (t < 0) t += 1;
  248. if (t > 1) t -= 1;
  249. if (t < 1 / 6) return p + (q - p) * 6 * t;
  250. if (t < 1 / 2) return q;
  251. if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
  252. return p;
  253. }
  254.  
  255. function hslToRgb(h, s, l) {
  256. let r, g, b;
  257.  
  258. if (s == 0)
  259. r = g = b = l; // achromatic
  260. else {
  261. let q = l < 0.5 ? l * (1 + s) : l + s - l * s;
  262. let p = 2 * l - q;
  263. r = hue2rgb(p, q, h + 1 / 3);
  264. g = hue2rgb(p, q, h);
  265. b = hue2rgb(p, q, h - 1 / 3);
  266. }
  267.  
  268. return ({
  269. r: Math.round(r * 255),
  270. g: Math.round(g * 255),
  271. b: Math.round(b * 255),
  272. });
  273. }
  274. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址