// ==UserScript==
// @name Modify Traces
// @namespace https://greasyfork.org/users/30701-justins83-waze
// @version 2018.11.07.01
// @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==
/* global W */
/* global OL */
/* ecmaVersion 2017 */
/* global $ */
/* global _ */
/* global WazeWrap */
/* global require */
/* eslint curly: ["warn", "multi-or-nest"] */
(function() {
'use strict';
var URMO;
var recoloredArrow = "";
var recoloredUserArrow = "";
var img = new Image();
var userArrow = 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();
});
getModifiedUserArrow().then(result => {
val.styleMap.styles.default.rules[userRouteArrowIndex].symbolizer.externalGraphic = recoloredUserArrow;
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.
});
}
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 getModifiedUserArrow(tries = 1){
return new Promise((resolve, reject) =>{
if(recoloredUserArrow === ""){
if(tries <= 50)
setTimeout(() => resolve(getModifiedUserArrow(tries++)), 100);
}
else
resolve(recoloredUserArrow);
});
}
function URLayerPopulated(mutations){
mutations.forEach(function(mutation) {
for (var i = 0; i < mutation.addedNodes.length; i++) {
var addedNode = mutation.addedNodes[i];
if (addedNode.nodeType === Node.ELEMENT_NODE && $(addedNode).hasClass('mapUpdateRequest'))
modifyRules();
}
});
}
function init(){
img.crossOrigin = "anonymous";
img.onload = recolorArrow;
img.src = "https://editor-assets.waze.com/production/img/one-way-routed9aa340910f8fc7a0fd2285fa0aab968.png";
userArrow.crossOrigin = "anonymous";
userArrow.onload = recolorUserArrow;
userArrow.src = "https://editor-assets.waze.com/production/img/one-way-drivee7f57df07fa6d5f61eee9b71ae5e18b1.png";
URMO = new MutationObserver(URLayerPopulated);
URMO.observe($('#panel-container')[0], {childList : true, subtree: true});
}
//changes the purple Waze drive arrows to white for more contrast.
function recolorArrow() {
let canvas = document.createElement('canvas');
let 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;
}
}
let mycanvas = document.createElement('canvas');
$(mycanvas).attr('width', 9);
$(mycanvas).attr('height', 5);
let newctx = mycanvas.getContext('2d');
newctx.putImageData(imgData,0,0);
recoloredArrow = mycanvas.toDataURL();
}
function recolorUserArrow() {
let canvas = document.createElement('canvas');
let ctx = canvas.getContext("2d");
ctx.drawImage(userArrow, 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 green pixels to the new color
if (hue > 157 && hue < 160) {
var newRgb = hslToRgb((hue - 157)/360, .037, .106);//hsl.l);
data[i + 0] = newRgb.r;
data[i + 1] = newRgb.g;
data[i + 2] = newRgb.b;
}
}
let mycanvas = document.createElement('canvas');
$(mycanvas).attr('width', 9);
$(mycanvas).attr('height', 5);
let newctx = mycanvas.getContext('2d');
newctx.putImageData(imgData,0,0);
recoloredUserArrow = 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),
});
}
})();