WME Mapraid Overlays

Mapraid overlays

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name             WME Mapraid Overlays
// @namespace        https://greasyfork.org/en/users/166843-wazedev
// @version          2024.05.29.01
// @description      Mapraid overlays
// @author           JustinS83
// @include          https://www.waze.com/editor*
// @include          https://www.waze.com/*/editor*
// @include          https://beta.waze.com/editor*
// @include          https://beta.waze.com/*/editor*
// @exclude          https://www.waze.com/*user/editor*
// @grant            GM_xmlhttpRequest
// @connect          api.github.com
// @connect          raw.githubusercontent.com
// @require          https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @contributionURL  https://github.com/WazeDev/Thank-The-Authors
// ==/UserScript==

/* global W */
/* global OL */
/* ecmaVersion 2017 */
/* global $ */
/* global I18n */
/* global _ */
/* global WazeWrap */
/* global require */
/* eslint curly: ["warn", "multi-or-nest"] */

(function() {
    'use strict';

    var _settings;
    var _settingsStoreName = '_wme_mapraid_overlays';
    var _kml;
    var _layerName = 'Mapraid Overlay';
    var _layer = null;
    var countryAbbr;
    var _origOpacity;
    var _mapraidNameMap = {};

    function bootstrap(tries = 1) {
        if (W &&
            W.map &&
            W.model &&
            W.loginManager.user &&
            W.model.getTopCountry() &&
            $ && WazeWrap.Ready)
            init();
        else if (tries < 1000)
            setTimeout(function () {bootstrap(++tries);}, 200);
    }

    bootstrap();

    function isChecked(checkboxId) {
        return $('#' + checkboxId).is(':checked');
    }

    function setChecked(checkboxId, checked) {
        $('#' + checkboxId).prop('checked', checked);
    }

    function loadSettings() {
        _settings = $.parseJSON(localStorage.getItem(_settingsStoreName));
        let _defaultsettings = {
            layerVisible: true,
            EnabledOverlays: {},
            HideCurrentArea: false
        };
        _settings = $.extend({}, _defaultsettings, _settings);
    }

    function saveSettings() {
        if (localStorage) {
            var settings = {
                layerVisible: _layer.visibility,
                EnabledOverlays: _settings.EnabledOverlays,
                HideCurrentArea: _settings.HideCurrentArea
            };
            localStorage.setItem(_settingsStoreName, JSON.stringify(settings));
        }
    }

    async function getKML(url){
        return await wrapGMXMLHTTP(url); //$.get(url);
    }

    async function wrapGMXMLHTTP(url){
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                url,
                method: 'GET',
                onload(res) {
                    if (res.status < 400) {
                        resolve(res.responseText);
                    } else {
                        console.log("error");
                        console.log(res.status);
                        // handle errors here
                    }
                },
                onerror(res) {
                    // handle errors here
                    console.log("Error:");
                    console.log(res.text);
                }
            });
        });
    }

    function GetFeaturesFromKMLString(strKML) {
        var format = new OpenLayers.Format.KML({
            'internalProjection': W.map.getProjectionObject(),
            'externalProjection': new OpenLayers.Projection("EPSG:4326"),
            'extractStyles': true
        });
        return format.read(strKML);
    }

    async function init(){
        loadSettings();

        var layerid = 'wme_mapraid_overlays';

        _layer = new OpenLayers.Layer.Vector("Mapraid Overlays", {
            rendererOptions: { zIndexing: true },
            uniqueName: layerid,
            layerGroup: 'mapraid_overlays',
            zIndex: -9999,
            visibility: _settings.layerVisible
        });
        I18n.translations[I18n.locale].layers.name[layerid] = "Mapraid Overlays";
        W.map.addLayer(_layer);

        var $section = $("<div>", {style:"padding:8px 16px", id:"WMEMapraidOverlays"});
        $section.html([
            `<h4 style="margin-bottom:0px;"><b>WME Mapraid Overlays</b></h4>`,
            `<h6 style="margin-top:0px;">${GM_info.script.version}</h6>`,
            `<div><input type="checkbox" id="_cbMROHideCurrentArea" class="wmemroSettingsCheckbox" /><label for="_cbMROHideCurrentArea">Hide fill for current area</label></div>`,
            `<div id="divWMEMROAvailableOverlays"><label>Available overlays</label> <select id="mroOverlaySelect" style="min-width:125px;"></select><i class="fa fa-plus fa-lg" id="mroAddOverlay" aria-hidden="true" style="color:green; cursor:pointer;"></i></div>`,
            '<div id="currOverlays"></div>',
            '<div style="position:absolute; bottom:0;">Generate new mapraid overlays at <a href="http://wazedev.com/mapraidgenerator.html" target="_blank">http://wazedev.com/mapraidgenerator.html</a></div>',
            '</div>'
        ].join(' '));

        WazeWrap.Interface.Tab('MRO', $section.html(), init2, 'MRO');
    }

    async function getAvailableOverlays(){
        $('#mroOverlaySelect').innerHTML = "";
        countryAbbr = W.model.getTopCountry().attributes.abbr;
        let KMLinfoArr = $.parseJSON(await wrapGMXMLHTTP(`https://api.github.com/repos/WazeDev/WME-Mapraid-Overlays/contents/KMLs/${countryAbbr}`));
        let overlaysSelect = $('<div>');

        overlaysSelect.html([
            '<option selected disabled hidden style="display: none" value=""></option>',
            `${KMLinfoArr.map(function(obj){
                let fileName = obj.name.replace(".kml", "");
                if(!_settings.EnabledOverlays[fileName])
                    return `<option value="${fileName}">${fileName}</option>`;
            })}`,
            '</select>'
        ].join(''));
        $('#mroOverlaySelect')[0].innerHTML = overlaysSelect.html();
    }

    function updatePolygons(newKML, mapraidName){
        var _features = GetFeaturesFromKMLString(newKML);

        for(let i=0; i< _features.length; i++){
            _features[i].attributes.name = _features[i].attributes.name.replace('<at><openparen>', '').replace('<closeparen>','');
            _features[i].style.label = _features[i].attributes.name;
            _features[i].style.labelOutlineColor= '#000000';
            _features[i].style.labelOutlineWidth= 4;
            _features[i].style.labelAlign= 'cm';
            _features[i].style.fontSize= "16px";
            _features[i].style.fontColor= _features[i].style.fillColor;//"#ffffff";
            _features[i].attributes.mapraidName = mapraidName;

            if(!_settings.EnabledOverlays[mapraidName].fillAreas){
                if(!_origOpacity)
                    _origOpacity = _features[i].style.fillOpacity;
                _features[i].style.fillOpacity = 0;
            }
        }

        _layer.addFeatures(_features);
    }

    function hex_is_light(color) {
        const hex = color.replace('#', '');
        const c_r = parseInt(hex.substr(0, 2), 16);
        const c_g = parseInt(hex.substr(2, 2), 16);
        const c_b = parseInt(hex.substr(4, 2), 16);
        const brightness = ((c_r * 299) + (c_g * 587) + (c_b * 114)) / 1000;
        return brightness > 70;
    }

    async function BuildEnabledOverlays(mapraidName){
        let kml;
        try{
            kml = await getKML(encodeURI(`https://raw.githubusercontent.com/WazeDev/WME-Mapraid-Overlays/master/KMLs/${countryAbbr}/${mapraidName}.kml`));
        }
        catch(err){
            return;
            console.error(err);
        }
        let kmlObj = $($.parseXML(kml));
        let RaidAreas = $(kmlObj).find('Placemark');

        let $newRaidSection = $('<div>');
        $newRaidSection.html([
            `<fieldset style="border:1px solid silver; padding:8px; border-radius:4px; position:relative;"><legend style="margin-bottom:0px; borer-bottom-style:none; width:auto;"><h4>${mapraidName}</h4></legend>`,
            `<i class="fa fa-minus fa-lg" id="mroRemoveOverlay${mapraidName.replace(/\s/g, "_")}" aria-hidden="true" style="color:red; position:absolute; cursor:pointer; top:10px; right:5px;"></i>`,
            `<div><input type="checkbox" id="_cbMROFillRaidArea${mapraidName.replace(/\s/g, "_")}" ${_settings.EnabledOverlays[mapraidName].fillAreas ? 'checked' : ''} /><label for="_cbMROFillRaidArea${mapraidName.replace(/\s/g, "_")}">Fill raid area</label></div>`,
            `Jump to <select id="${mapraidName.replace(/\s/g, "_")}_Areas">${
            function(){
                let names = $(RaidAreas).find('name');
                let options = "";
                for(let i=0; i<names.length; i++)
                    options += `<option>${$(names[i]).text()}</option>`;
                return options;
            }()
            }</select>`,
            `<i class="fa fa-share" aria-hidden="true" style="color:green; cursor:pointer;" id="JumpTo${mapraidName.replace(/\s/g, "_")}"></i>`,
            '</fieldset>'
        ].join(''));

        $(`#mroOverlaySelect option[value="${mapraidName}"]`).remove(); //remove this option from the list
        $('#currOverlays').append($newRaidSection.html()); //add the mapraid section

        $('[id^="_cbMROFillRaidArea"]').change(function(){
            let mapraid = this.id.replace("_cbMROFillRaidArea", "");
            _settings.EnabledOverlays[_mapraidNameMap[mapraid]].fillAreas = isChecked(this.id);
            saveSettings();
        });

        $('[id^="mroRemoveOverlay"]').click(function(){
            let mapraid = this.id.replace("mroRemoveOverlay", "");
            $(this).parent().remove();

            delete _settings.EnabledOverlays[_mapraidNameMap[mapraid]];
            saveSettings();

            let deleteFeatures = [];
            for(let i=0; i < _layer.features.length; i++){ //delete the features from the layer
                if(_layer.features[i].attributes.mapraidName === _mapraidNameMap[mapraid])
                    deleteFeatures.push(_layer.features[i]);
            }
            _layer.removeFeatures(deleteFeatures);
            getAvailableOverlays();
        });

        $('[id^=_cbMROFillRaidArea]').change(function(){
            let mapraid = this.id.replace("_cbMROFillRaidArea", "");
            for(let i=0; i<_layer.features.length; i++){
                if(_layer.features[i].attributes.mapraidName.replace(/\s/g, "_") === mapraid){
                    if(!_origOpacity)
                        _origOpacity = _layer.features[i].style.fillOpacity;
                    _layer.features[i].style.fillOpacity = isChecked(this.id) ? _origOpacity : 0;
                    _layer.redraw();
                }
            }
        });

        $('[id^="JumpTo"]').click(function(){
            //jump to the appropriate area - look up the area in the layer features and jump to the centroid.
            let raidArea = this.id.replace("JumpTo", "");
            for(let i=0; i<_layer.features.length; i++){
                if(_layer.features[i].attributes.mapraidName.replace(/\s/g, "_") === raidArea){
                    let selectedArea = $(`#${raidArea.replace(/\s/g, "_")}_Areas`).val();
                    if(_layer.features[i].attributes.name === selectedArea){
                        let centroid = _layer.features[i].geometry.getCentroid();
                        W.map.setCenter(new OL.LonLat(centroid.x, centroid.y), W.map.zoom)
                        break;
                    }
                }
            }

        });

        updatePolygons(kml, mapraidName);
    }

    function HandleMoveZoom(){
        //display the current MR area in the title bar
        //hide the current MR area fill (if setting is enabled)

        if($('#mrodivCurrMapraidArea').length === 0){
            var $section = $("<div>");
            $section.html([
                '<div id="mrodivCurrMapraidArea" style="font-size: 16px; font-weight:bold; margin-left:10px; float:left;">',
                '<span id="mroCurrAreaTopbar"></span>',
                '</div>'
            ].join(' '));

            $('.topbar').append($section.html());
        }

        let center = new OpenLayers.Geometry.Point(W.map.getCenter().lon,W.map.getCenter().lat);
        $('#mroCurrAreaTopbar').text("");
        for (var i=0;i<_layer.features.length;i++){
            var feature = _layer.features[i];
            if(_origOpacity && _settings.EnabledOverlays[feature.attributes.mapraidName].fillAreas)
                feature.style.fillOpacity = _origOpacity;
            if(feature.geometry.intersects(center)){
                $('#mroCurrAreaTopbar').text(feature.attributes.name);
                $('#mroCurrAreaTopbar').css('color', feature.style.fillColor);

                if(!hex_is_light(feature.style.fillColor))
                    $('#mroCurrAreaTopbar').css('text-shadow', '-1px 0 #efefef, 0 1px #efefef, 1px 0 #efefef, 0 -1px #efefef');
                else
                    $('#mroCurrAreaTopbar').css('text-shadow', '-1px 0 black, 0 1px black, 1px 0 black, 0 -1px black');


                if(_settings.HideCurrentArea){
                    if(!_origOpacity)
                        _origOpacity = feature.style.fillOpacity;
                    if(feature.style.fillOpacity > 0)
                        feature.style.fillOpacity = 0;
                }
            }
        }
        _layer.redraw();
    }

    function init2(){
        getAvailableOverlays();

        $.each(_settings.EnabledOverlays, function(k, v){
            if(!_mapraidNameMap[k.replace(/\s/g, "_")])
                _mapraidNameMap[k.replace(/\s/g, "_")] = k;
            BuildEnabledOverlays(k);

        });

        $('#mroAddOverlay').click(async function(){
            if($('#mroOverlaySelect').val() !== null){
                let raid = $('#mroOverlaySelect').val();
                _settings.EnabledOverlays[raid] = {fillAreas: true};

                BuildEnabledOverlays(raid);
                if(!_mapraidNameMap[raid.replace(/\s/g, "_")])
                    _mapraidNameMap[raid.replace(/\s/g, "_")] = raid;

                saveSettings();
            }
        });

        $('.wmemroSettingsCheckbox').change(function(){
            var settingName = $(this)[0].id.substr(6);
            _settings[settingName] = this.checked;
            saveSettings();
        });

        $('#_cbMROHideCurrentArea').change(function(){
            HandleMoveZoom();
        });

        WazeWrap.Events.register("zoomend", null, HandleMoveZoom);
        WazeWrap.Events.register("moveend", null, HandleMoveZoom);

        setChecked('_cbMROHideCurrentArea', _settings.HideCurrentArea);
        HandleMoveZoom();
    }

})();