- // ==UserScript==
- // @name Modify Traces
- // @namespace https://greasyfork.org/users/30701-justins83-waze
- // @version 0.3
- // @description Modify the Waze & User trace displayed by URs
- // @author JustinS83
- // @include https://www.waze.com/editor*
- // @include https://www.waze.com/*/editor*
- // @include https://beta.waze.com*
- // @exclude https://www.waze.com/*user/editor*
- // @grant none
- // ==/UserScript==
-
- (function() {
- 'use strict';
-
- var URMO;
- var recoloredArrow = "";
- var img = new Image();
- var mIcon;
-
- function bootstrap(tries = 1) {
-
- if (W &&
- W.map &&
- W.model &&
- W.loginManager.user &&
- $) {
- init();
- } else if (tries < 1000) {
- setTimeout(function () {bootstrap(tries++);}, 200);
- }
- }
-
- bootstrap();
-
- function modifyRules(){
- getTraceLayer().then(val => {
- //In theory these are always the same index - but better to search and be sure we get the right ones
- let sugRouteArrowIndex = val.styleMap.styles.default.rules.findIndex(function(e){ return e.filter.value == "suggestedRouteArrow";});
- let sugRouteIndex = val.styleMap.styles.default.rules.findIndex(function(e){ return e.filter.value == "suggestedRoute";});
- let userRouteArrowIndex = val.styleMap.styles.default.rules.findIndex(function(e){ return e.filter.value == "driveArrow";});
- let userRouteIndex = val.styleMap.styles.default.rules.findIndex(function(e){ return e.filter.value == "drive";});
-
- //Waze suggested route
- //default is 5
- val.styleMap.styles.default.rules[sugRouteArrowIndex].symbolizer.graphicHeight = 8;
- //default is 9
- val.styleMap.styles.default.rules[sugRouteArrowIndex].symbolizer.graphicWidth = 12;
-
- //User driven route
- //default is 5
- val.styleMap.styles.default.rules[userRouteArrowIndex].symbolizer.graphicHeight = 8;
- //default is 9
- val.styleMap.styles.default.rules[userRouteArrowIndex].symbolizer.graphicWidth = 12;
- //This would change the route color from dark purple
- //val.styleMap.styles.default.rules[sugRouteIndex].symbolizer.strokeColor = "#c77aff";
-
- getModifiedArrow().then(result => {
- val.styleMap.styles.default.rules[sugRouteArrowIndex].symbolizer.externalGraphic = recoloredArrow;
- val.redraw();
- });
-
- val.redraw();
- 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.
- for(var mObj in W.map.updateRequestLayer.markers){
- if(W.map.updateRequestLayer.markers.hasOwnProperty(mObj)){
- mIcon = W.map.updateRequestLayer.markers[mObj].icon.div;
- mIcon.removeEventListener("click", modifyRules, false);
- }
- }
- });
-
- }
-
- 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
- return new Promise((resolve, reject) => {
- if (W.map.getLayersByName("problemMoreInfo").length > 0){
- resolve(W.map.getLayersByName("problemMoreInfo")[0]);
- } else {
- if(tries <= 10)
- setTimeout(() => resolve(getTraceLayer(tries++)), 100);
- }
- });
- }
-
- function getModifiedArrow(tries = 1){
- return new Promise((resolve, reject) =>{
- if(recoloredArrow === ""){
- if(tries <= 50)
- setTimeout(() => resolve(getModifiedArrow(tries++)), 100);
- }
- else{
- resolve(recoloredArrow);
- }
- });
- }
-
- function URLayerPopulated()
- {
- for(var mObj in W.map.updateRequestLayer.markers){
- if(W.map.updateRequestLayer.markers.hasOwnProperty(mObj)){
- mIcon = W.map.updateRequestLayer.markers[mObj].icon.div;
- mIcon.addEventListener("click", modifyRules, false);
- }
- }
- }
-
- function init(){
- URMO = new MutationObserver(URLayerPopulated);
- URMO.observe(W.map.updateRequestLayer.div, {childList : true});
-
- img.crossOrigin = "anonymous";
- img.onload = recolorArrow;
- img.src = "https://editor-assets.waze.com/production/img/one-way-routed9aa340910f8fc7a0fd2285fa0aab968.png";
- }
-
- //changes the purple Waze drive arrows to yellow for more contrast. Ugly, but effective. Like your mom.
- function recolorArrow() {
- var canvas = document.createElement('canvas');
- var ctx = canvas.getContext("2d");
- ctx.drawImage(img, 0, 0);
- let imgData = ctx.getImageData(0, 0, 9, 5);
- let data = imgData.data;
-
- for (var i = 0; i < data.length; i += 4) {
- let red = data[i + 0];
- let green = data[i + 1];
- let blue = data[i + 2];
- let alpha = data[i + 3];
-
- // skip transparent/semiTransparent pixels
- if (alpha < 10)
- continue;
-
- let hsl = rgbToHsl(red, green, blue);
- let hue = hsl.h * 360;
-
- // change purple pixels to the new color
- if (hue > 260 && hue < 270) {
- var newRgb = hslToRgb((hue - 200)/360, hsl.s, 100);//hsl.l); //Setting l to 100 forces it to white
- data[i + 0] = newRgb.r;
- data[i + 1] = newRgb.g;
- data[i + 2] = newRgb.b;
- //data[i + 3] = 255;
- }
- }
- var mycanvas = document.createElement('canvas');
- $(mycanvas).attr('width', 9);
- $(mycanvas).attr('height', 5);
- var newctx = mycanvas.getContext('2d');
- newctx.putImageData(imgData,0,0);
- recoloredArrow = mycanvas.toDataURL();
- }
-
- function rgbToHsl(r, g, b) {
- r /= 255;
- g /= 255;
- b /= 255;
- let max = Math.max(r, g, b),
- min = Math.min(r, g, b);
- let h, s, l = (max + min) / 2;
-
- if (max == min)
- h = s = 0; // achromatic
- else {
- let d = max - min;
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
- switch (max) {
- case r:
- h = (g - b) / d + (g < b ? 6 : 0);
- break;
- case g:
- h = (b - r) / d + 2;
- break;
- case b:
- h = (r - g) / d + 4;
- break;
- }
- h /= 6;
- }
-
- return ({
- h: h,
- s: s,
- l: l,
- });
- }
-
- function hue2rgb(p, q, t) {
- if (t < 0) t += 1;
- if (t > 1) t -= 1;
- if (t < 1 / 6) return p + (q - p) * 6 * t;
- if (t < 1 / 2) return q;
- if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
- return p;
- }
-
- function hslToRgb(h, s, l) {
- let r, g, b;
-
- if (s == 0)
- r = g = b = l; // achromatic
- else {
- let q = l < 0.5 ? l * (1 + s) : l + s - l * s;
- let p = 2 * l - q;
- r = hue2rgb(p, q, h + 1 / 3);
- g = hue2rgb(p, q, h);
- b = hue2rgb(p, q, h - 1 / 3);
- }
-
- return ({
- r: Math.round(r * 255),
- g: Math.round(g * 255),
- b: Math.round(b * 255),
- });
- }
- })();