Discussion for the unofficial, community-developed addons, extensions and scripts built for the Waze Map Editor.

The official index of these tools is the Community Plugins, Extensions and Tools wiki page.
Post by milkboy
Hi! I made a new version (1.5.8) with some changes from several contributors. It's available at the original userscripts page, on Github and soon the browser extensions for Chrome & Firefox should also be updated (takes a while, especially for the Firefox extension being #86 in the review queue).

Sorry for the big delay, been kind of busy with "real life" ( I know, lame excuse).

Update 2015-02-03: If you use a grease/tampermonkey script version earlier than 1.6.1, please fetch a new version from GitHub https://raw.githubusercontent.com/milkb ... le.user.js, as the autoupdate URL was changed to GitHub.

Update 2015-02-04: Added script to greasyforg.org also for easier installation https://greasyfork.org/en/scripts/7887- ... angle-info
It's updated automatically from GitHub sources, so feel free to use GF as source =)
milkboy
Map Editor - level 3
Map Editor - level 3
Posts: 107
Has thanked: 10 times
Been thanked: 123 times
Send a message
Last edited by milkboy on Wed Feb 04, 2015 6:01 am, edited 2 times in total.
Nexus 5 | CM 13 (Android 6.0.1 nightly)
[img]https:///c7J4Vm[/img][img]https:///EFna5T[/img][img]https:///a349MJ[/img]
Škoda Octavia III Combi 2.0 TDI RS DSG 2014 https://images.spritmonitor.de/643660_5.png

Post by milkboy
sketch wrote:Hey, it doesn't seem to be working in the beta editor. I believe the issue is with the "include" code:

Code: Select all

// @include             /^https:\/\/www\.waze\.com\/(.{2,6}\/)?(beta_)?editor\/.*$/
I don't entirely speak code, but this seems to envision "http://www.waze.com/beta_editor/" as the location of the beta editor, while the actual location is "http://editor-beta.waze.com/editor/".

Thanks!
Meh. The URL changed again? That kind of sucks, because the browser add-ons usually get disabled by default when the URL:s they run on changes (a nice security measure yes, but inconvenient for users). But thank you for the notice. I'll fix that and try to make translations work also asap.
milkboy
Map Editor - level 3
Map Editor - level 3
Posts: 107
Has thanked: 10 times
Been thanked: 123 times
Send a message
Nexus 5 | CM 13 (Android 6.0.1 nightly)
[img]https:///c7J4Vm[/img][img]https:///EFna5T[/img][img]https:///a349MJ[/img]
Škoda Octavia III Combi 2.0 TDI RS DSG 2014 https://images.spritmonitor.de/643660_5.png

Post by milkboy
Anyway, made a new version that seems to work nicely in the beta editor also. (Only tested in practice mode, as I don't have real access).

Also fixed the translation issue, so the one and only word being displayed anywhere (the layer name) is now translated for Swedish editor users. yay \o/
milkboy
Map Editor - level 3
Map Editor - level 3
Posts: 107
Has thanked: 10 times
Been thanked: 123 times
Send a message
Nexus 5 | CM 13 (Android 6.0.1 nightly)
[img]https:///c7J4Vm[/img][img]https:///EFna5T[/img][img]https:///a349MJ[/img]
Škoda Octavia III Combi 2.0 TDI RS DSG 2014 https://images.spritmonitor.de/643660_5.png

Post by milkboy
MGODLEW wrote:I would assume it would be pretty easy to implement, I only have basic coding knowledge by I would imagine the code would be something like this: If road segment "A" = Freeway + If road segment "B" = Freeway & Middle Angle = 0 - 45 degrees then display angle # Blue = "Stay to/Keep to"
In theory this is easy. In the real world, the instructions are not always equal even if the segments and angles seem to be equal. It could be possible to make some educated guesses though, and I'll look into it when I have some spare time.
milkboy
Map Editor - level 3
Map Editor - level 3
Posts: 107
Has thanked: 10 times
Been thanked: 123 times
Send a message
Nexus 5 | CM 13 (Android 6.0.1 nightly)
[img]https:///c7J4Vm[/img][img]https:///EFna5T[/img][img]https:///a349MJ[/img]
Škoda Octavia III Combi 2.0 TDI RS DSG 2014 https://images.spritmonitor.de/643660_5.png

Post by milkboy
tkr85 wrote:Working Version :)
Based on code from milkboy's GitHub.
What was fixed ?
In general:

Code: Select all

selectedItems[i].attributes   => selectedItems[i].model.attributes
and some minor changes.

Code: Select all

// ==UserScript==
// @name                WME Junction Angle info
// @namespace           http://userscripts.org/users/508112
// @description         Show the angle between two selected (and connected) segments
// @include             /^https:\/\/(www|editor-beta)\.waze\.com\/(.{2,6}\/)?editor\/.*$/
// @version             1.5.9.1
// @grant               none
// @copyright		2013 Michael Wikberg <michael@wikberg.fi>
// @license CC-BY-NC-SA
// ==/UserScript==

/**
 * Copyright 2014 Michael Wikberg <waze@wikberg.fi>
 * WME Junction Angle Info extension is licensed under a Creative Commons
 * Attribution-NonCommercial-ShareAlike 3.0 Unported License.
 *
 * Contributions by:
 *     2014 Paweł Pyrczak "tkr85" <support@pyrczak.pl>
 *     2014 "AlanOfTheBerg" <alanoftheberg@gmail.com>
 *     2014 "berestovskyy" <?>
 */

function run_ja() {

    var junctionangle_version = "1.5.9";
    var junctionangle_debug = 1;	//0: no output, 1: basic info, 2: debug 3: crazy debug
    var $;
    var ja_features = [];

    function ja_bootstrap() {
        try {
            if ((typeof window.Waze.map != undefined) && (undefined != typeof window.Waze.map.events.register) && (undefined != typeof window.Waze.selectionManager.events.register ) && (undefined != typeof window.Waze.loginManager.events.register)) {
                setTimeout(junctionangle_init, 500);
            } else {
                setTimeout(ja_bootstrap, 1000);
            }
        } catch (err) {
            setTimeout(ja_bootstrap, 1000);
        }
    }

    function ja_log(ja_log_msg, ja_log_level) {
        if (ja_log_level <= junctionangle_debug) {
            if (typeof ja_log_msg == "object") {
                //ja_log(arguments.callee.caller.toString(), ja_log_level);
                console.log(ja_log_msg);
            }
            else {
                console.log("WME Junction Angle: " + ja_log_msg);
            }
        }
    }

    function junctionangle_init() {

        //Listen for selected nodes change event
        window.Waze.selectionManager.events.register("selectionchanged", null, ja_calculate);

        window.Waze.model.segments.events.on({
            "objectschanged": ja_calculate,
            "objectsremoved": ja_calculate
        });
        window.Waze.model.nodes.events.on({
            "objectschanged": ja_calculate,
            "objectsremoved": ja_calculate
        });

        //HTML changes after login, even though the page is not reloaded. Better do init again.
        window.Waze.loginManager.events.register("afterloginchanged", null, junctionangle_init);

        /**
         * Make some style settings
         */
        var ja_style = new window.OpenLayers.Style({
            fillColor: "#ffcc88",
            strokeColor: "#ff9966",
            strokeWidth: 2,
            label: "${angle}",
            fontWeight: "bold",
            pointRadius: 10,
            fontSize: "10px"
        }, {
            rules: [
                new window.OpenLayers.Rule({
                    symbolizer: {
                    }
                }),
                new window.OpenLayers.Rule({
                    filter: new window.OpenLayers.Filter.Comparison({
                        type: window.OpenLayers.Filter.Comparison.EQUAL_TO,
                        property: "ja_type",
                        value: "junction"
                    }),
                    symbolizer: {
                        pointRadius: 13,
                        fontSize: "12px",
                        fillColor: "#4cc600",
                        strokeColor: "#183800"
                    }
                })
            ]
        });

        //Add support for translations. Default (and fallback) is "en".
        //Note, don't make typos in "acceleratorName", as it has to match the layer name (with whitespace removed
        // to actually work. Took me a while to figure that out...
        I18n.translations.en.layers.name["junction_angles"] = "Junction Angles";

        switch(window.I18n.locale) {
            case 'sv':
                I18n.translations.sv.layers.name["junction_angles"] = "Korsningsvinklar";
                break;
            case 'fi':
                I18n.translations.fi.layers.name["junction_angles"] = "Risteyskulmat";
                break;
        }

        layername = I18n.translate("layers.name.junction_angles","bar");

        //try to see if we already have a layer
        if (window.Waze.map.getLayersBy("uniqueName","junction_angles").length == 0) {

            // Create a vector layer and give it your style map.
            ja_mapLayer = new window.OpenLayers.Layer.Vector(layername, {
                displayInLayerSwitcher: true,
                uniqueName: "junction_angles",
                shortcutKey: "S+j",
                accelerator: "toggle" + layername.replace(/\s+/g,''),
                className: "junction-angles",
                styleMap: new window.OpenLayers.StyleMap(ja_style)
            });

            window.Waze.map.addLayer(ja_mapLayer);
            ja_log("version " + junctionangle_version + " loaded.", 0);

            ja_log(window.Waze.map, 3);
            ja_log(window.Waze.model, 3);
            ja_log(window.Waze.loginManager, 3);
            ja_log(window.Waze.selectionManager, 3);
            ja_log(ja_mapLayer, 3);
            ja_log(window.OpenLayers, 3);
        } else {
            ja_log("Oh, nice.. We already had a layer?", 3);
        }
    }

    function ja_calculate() {
        //clear old info
        ja_mapLayer.destroyFeatures();

        //try to show all angles for all selected segments
        if (window.Waze.selectionManager.selectedItems.length == 0) return 1;
        ja_log("Checking junctions for " + window.Waze.selectionManager.selectedItems.length + " segments", 2);
        var ja_nodes = [];

        for (i = 0; i < window.Waze.selectionManager.selectedItems.length; i++) {
            ja_log(window.Waze.selectionManager.selectedItems[i], 3);
            switch (window.Waze.selectionManager.selectedItems[i].model.type) {
                case "node":
                    ja_nodes.push(window.Waze.selectionManager.selectedItems[i].model.attributes.id);
                    break;
                case "segment":
                    //segments selected?
                    if (window.Waze.selectionManager.selectedItems[i].model.attributes.fromNodeID != null &&
                        ja_nodes.indexOf(window.Waze.selectionManager.selectedItems[i].model.attributes.fromNodeID) == -1) {
                        ja_nodes.push(window.Waze.selectionManager.selectedItems[i].model.attributes.fromNodeID);
                    }
                    if (ja_nodes.indexOf(window.Waze.selectionManager.selectedItems[i].model.attributes.toNodeID != null &&
                        ja_nodes.indexOf(window.Waze.selectionManager.selectedItems[i].model.attributes.toNodeID) == -1)) {
                        ja_nodes.push(window.Waze.selectionManager.selectedItems[i].model.attributes.toNodeID);
                    }
                    break;
                default:
                    ja_log("Found unknown item type: " + window.Waze.selectionManager.selectedItems[i].model.type, 1);
            }
        }

        ja_features = [];

        for (i = 0; i < ja_nodes.length; i++) {
            node = window.Waze.model.nodes.get(ja_nodes[i]);
            if (node == null || !node.hasOwnProperty('attributes')) {
                //Oh oh.. should not happen?
                ja_log("Oh oh.. should not happen?",1);
                ja_log(ja_nodes, 2);
                ja_log(window.Waze.model, 3);
                ja_log(window.Waze.model.nodes, 3);
                continue;
            }
            //check connected segments
            segments = node.attributes.segIDs;
            ja_log(node, 2);

            //ignore of we have less than 2 segments
            if (segments.length <= 1) {
                ja_log("Found only " + segments.length + " connected segments at " + ja_nodes[i] + ", not calculating anything...", 2);
                continue;
            }

            ja_log("Calculating angles for " + segments.length + " segments", 2);

            angles = [];
            selected_segments = 0;

            for (j = 0; j < segments.length; j++) {
                s = window.Waze.model.segments.get(segments[j]);
                a = ja_getAngle(ja_nodes[i], s);
                ja_log("j: " + j + "; Segment " + segments[j] + " angle is " + a, 3);
                angles[j] = [a, segments[j], s != null ? s.isSelected() : false];
                if (s != null ? s.isSelected() : false) selected_segments++;
            }

            ja_log(angles, 2);
            //sort angle data (ascending)
            angles.sort(function (a, b) {
                return a[0] - b[0]
            });
            ja_log(angles, 3);
            ja_log(selected_segments, 3);

            switch (window.Waze.map.zoom) {
                case 9:
                    ja_label_distance = 4;
                    break;
                case 8:
                    ja_label_distance = 8;
                    break;
                case 7:
                    ja_label_distance = 15;
                    break;
                case 6:
                    ja_label_distance = 25;
                    break;
                case 5:
                    ja_label_distance = 40;
                    break;
                case 4:
                    ja_label_distance = 80;
                    break;
                case 3:
                    ja_label_distance = 140;
                    break;
                case 2:
                    ja_label_distance = 300;
                    break;
                case 1:
                    ja_label_distance = 400;
                    break;
            }
            ja_log("zoom: " + window.Waze.map.zoom + " -> distance: " + ja_label_distance, 2);

            //if we have two connected segments selected, do some magic to get the turn angle only =)
            if (selected_segments == 2) {
                ja_selected = [];
                ja_extra_space_multiplier = 1;

                for (j = 0; j < angles.length; j++) {
                    if (angles[j][2]) {
                        ja_selected.push(angles[j]);
                    }
                }

                a = ((ja_selected[1][0] - ja_selected[0][0]) + 360) % 360;
                ha = (360 + (ja_selected[0][0] + ja_selected[1][0]) / 2) % 360;

                ja_log(a, 3);
                if (a < 60) {
                    ja_log("Sharp angle", 2);
                    ja_extra_space_multiplier = 2;
                }

                if (a > 180) {
                    //a2 = a - 180;
                    ha = ha + 180;
                }


                ja_log("Angle between " + ja_selected[0][1] + " and " + ja_selected[1][1] + " is " + a + " and position for label should be at " + ha, 3);

                //put the angle point
                ja_features.push(new window.OpenLayers.Feature.Vector(
                    new window.OpenLayers.Geometry.Point(
                        node.geometry.x + (ja_extra_space_multiplier * ja_label_distance * Math.cos((ha * Math.PI) / 180)),
                        node.geometry.y + (ja_extra_space_multiplier * ja_label_distance * Math.sin((ha * Math.PI) / 180))
                    )
                    , { angle: Math.round(Math.abs(180 - a)) + "°", ja_type: "junction" }
                ));
            }
            else {
                //get all segment angles
                for (j = 0; j < angles.length; j++) {
                    a = (360 + (angles[(j + 1) % angles.length][0] - angles[j][0])) % 360;
                    ha = (360 + ((a / 2) + angles[j][0])) % 360;

                    ja_log("Angle between " + angles[j][1] + " and " + angles[(j + 1) % angles.length][1] + " is " + a + " and position for label should be at " + ha, 3);
                    //push the angle point
                    ja_features.push(new window.OpenLayers.Feature.Vector(
                        new window.OpenLayers.Geometry.Point(
                            node.geometry.x + (ja_label_distance * Math.cos((ha * Math.PI) / 180)), node.geometry.y + (ja_label_distance * Math.sin((ha * Math.PI) / 180))
                        )
                        , { angle: Math.round(a) + "°", ja_type: "generic" }
                    ));
                }
            }
        }

        ja_log(ja_features, 2);
        //Update the displayed angles
        ja_mapLayer.addFeatures(ja_features);
    }

    function ja_points_equal(point1, point2) {
        return (point1.x == point2.x && point1.y == point2.y);
    }

    function ja_get_first_point(segment) {
        return segment.geometry.components[0];
    }

    function ja_get_last_point(segment) {
        return segment.geometry.components[segment.geometry.components.length - 1];
    }

    function ja_get_second_point(segment) {
        return segment.geometry.components[1];
    }

    function ja_get_next_to_last_point(segment) {
        return segment.geometry.components[segment.geometry.components.length - 2];
    }

    //get the absolute angle for a segment end point
    function ja_getAngle(ja_node, ja_segment) {
        if (ja_node == null || ja_segment == null) return null;
        if (ja_segment.attributes.fromNodeID == ja_node) {
            ja_dx = ja_get_second_point(ja_segment).x - ja_get_first_point(ja_segment).x;
            ja_dy = ja_get_second_point(ja_segment).y - ja_get_first_point(ja_segment).y;
        } else {
            ja_dx = ja_get_next_to_last_point(ja_segment).x - ja_get_last_point(ja_segment).x;
            ja_dy = ja_get_next_to_last_point(ja_segment).y - ja_get_last_point(ja_segment).y;
        }
        ja_log(ja_node + " / " + ja_segment + ": dx:" + ja_dx + ", dy:" + ja_dy);
        ja_angle = Math.atan2(ja_dy, ja_dx);
        return (360 + (ja_angle * 180 / Math.PI)) % 360;
    }

    ja_bootstrap();
}

//Dynamically create, add and run the script in the real page context
var DLscript = document.createElement("script");
DLscript.textContent = '' +
    run_ja.toString() + ' \n' +
    'run_ja();';
DLscript.setAttribute("type", "application/javascript");
document.body.appendChild(DLscript);

EDIT:
http://pyrczak.pl/j-A_160864.user.js
That was fast [emoji2] Getting too late here, but I'll check the addons tomorrow. (Did you submit a pull request on GH?)
milkboy
Map Editor - level 3
Map Editor - level 3
Posts: 107
Has thanked: 10 times
Been thanked: 123 times
Send a message
Nexus 5 | CM 13 (Android 6.0.1 nightly)
[img]https:///c7J4Vm[/img][img]https:///EFna5T[/img][img]https:///a349MJ[/img]
Škoda Octavia III Combi 2.0 TDI RS DSG 2014 https://images.spritmonitor.de/643660_5.png

Post by milkboy
brandonrossl wrote:Does anyone have the ability to update the official Chrome add-on?
Update being processed. I just did some quick tests and the update seemed to work. Report any problems once 1.5.10 is available in the chrome store =)

EDIT: May take up to 60 minutes still...
EDIT2: Seems to be available now
milkboy
Map Editor - level 3
Map Editor - level 3
Posts: 107
Has thanked: 10 times
Been thanked: 123 times
Send a message
Nexus 5 | CM 13 (Android 6.0.1 nightly)
[img]https:///c7J4Vm[/img][img]https:///EFna5T[/img][img]https:///a349MJ[/img]
Škoda Octavia III Combi 2.0 TDI RS DSG 2014 https://images.spritmonitor.de/643660_5.png

Post by milkboy
The Firefox addon will require some more time, as I need to install the whole developer environment from scratch (oh, and it may take several days to get the update published once it's ready)

EDIT: Firefox addon is at queue position 132/132...
milkboy
Map Editor - level 3
Map Editor - level 3
Posts: 107
Has thanked: 10 times
Been thanked: 123 times
Send a message
Nexus 5 | CM 13 (Android 6.0.1 nightly)
[img]https:///c7J4Vm[/img][img]https:///EFna5T[/img][img]https:///a349MJ[/img]
Škoda Octavia III Combi 2.0 TDI RS DSG 2014 https://images.spritmonitor.de/643660_5.png

Post by milkboy
milkboy wrote:EDIT: Firefox addon is at queue position 132/132...
Not sure what happened, but suddenly it was reviewed!? Usually it takes forever =D Any Wazers doing addon reviews?
milkboy
Map Editor - level 3
Map Editor - level 3
Posts: 107
Has thanked: 10 times
Been thanked: 123 times
Send a message
Nexus 5 | CM 13 (Android 6.0.1 nightly)
[img]https:///c7J4Vm[/img][img]https:///EFna5T[/img][img]https:///a349MJ[/img]
Škoda Octavia III Combi 2.0 TDI RS DSG 2014 https://images.spritmonitor.de/643660_5.png

Post by milkboy
I had a look at the flow chart (which is really nice, as it almost condenses the logic into code), so now the feature should be easy to implement :) I gave it a go a while back, but realized that the guesswork for routing instructions back then was only half correct. Anyway, please keep us posted on any updates to the flowchart. I might have a look at implementing something tomorrow [emoji16] but no promises yet.
milkboy
Map Editor - level 3
Map Editor - level 3
Posts: 107
Has thanked: 10 times
Been thanked: 123 times
Send a message
Nexus 5 | CM 13 (Android 6.0.1 nightly)
[img]https:///c7J4Vm[/img][img]https:///EFna5T[/img][img]https:///a349MJ[/img]
Škoda Octavia III Combi 2.0 TDI RS DSG 2014 https://images.spritmonitor.de/643660_5.png

Post by milkboy
Some progress yes. Hope to have something ready for alpha testing today =)

EDIT: Remove typos that happen when writing messages while feeding a child at the same time
milkboy
Map Editor - level 3
Map Editor - level 3
Posts: 107
Has thanked: 10 times
Been thanked: 123 times
Send a message
Nexus 5 | CM 13 (Android 6.0.1 nightly)
[img]https:///c7J4Vm[/img][img]https:///EFna5T[/img][img]https:///a349MJ[/img]
Škoda Octavia III Combi 2.0 TDI RS DSG 2014 https://images.spritmonitor.de/643660_5.png