PaulKoci / Pokemongomap.info S2 overlay

// ==UserScript==
// @name Pokemongomap.info S2 overlay
// @description Adds an overlay for pokemongomap.info website to show level14 - level17 S2 cells for pokéstops and gym placements.
// @version 1.1.0
// @include https://www.pokemongomap.info/*
// @copyright 2018, PaulKoci (https://openuserjs.org/users/PaulKoci); s2geometry script 2016 Jon Atkins & AJ ONeal, https://github.com/Daplie/s2-geometry.js
// @license ISC
// @grant none
// ==/UserScript==



var s2script = document.createElement('script');
s2script.textContent = "var S2={L:{}};S2.L.LatLng=function(t,e,r){var n=parseFloat(t,10),o=parseFloat(e,10);if(isNaN(n)||isNaN(o))throw new Error(\"Invalid LatLng object: (\"+t+\", \"+e+\")\");return r!==!0&&(n=Math.max(Math.min(n,90),-90),o=(o+180)%360+(-180>o||180===o?180:-180)),{lat:n,lng:o}},S2.L.LatLng.DEG_TO_RAD=Math.PI/180,S2.L.LatLng.RAD_TO_DEG=180/Math.PI,S2.LatLngToXYZ=function(t){var e=S2.L.LatLng.DEG_TO_RAD,r=t.lat*e,n=t.lng*e,o=Math.cos(r);return[Math.cos(n)*o,Math.sin(n)*o,Math.sin(r)]},S2.XYZToLatLng=function(t){var e=S2.L.LatLng.RAD_TO_DEG,r=Math.atan2(t[2],Math.sqrt(t[0]*t[0]+t[1]*t[1])),n=Math.atan2(t[1],t[0]);return S2.L.LatLng(r*e,n*e)};var largestAbsComponent=function(t){var e=[Math.abs(t[0]),Math.abs(t[1]),Math.abs(t[2])];return e[0]>e[1]?e[0]>e[2]?0:2:e[1]>e[2]?1:2},faceXYZToUV=function(t,e){var r,n;switch(t){case 0:r=e[1]/e[0],n=e[2]/e[0];break;case 1:r=-e[0]/e[1],n=e[2]/e[1];break;case 2:r=-e[0]/e[2],n=-e[1]/e[2];break;case 3:r=e[2]/e[0],n=e[1]/e[0];break;case 4:r=e[2]/e[1],n=-e[0]/e[1];break;case 5:r=-e[1]/e[2],n=-e[0]/e[2];break;default:throw{error:\"Invalid face\"}}return[r,n]};S2.XYZToFaceUV=function(t){var e=largestAbsComponent(t);t[e]<0&&(e+=3);var r=faceXYZToUV(e,t);return[e,r]},S2.FaceUVToXYZ=function(t,e){var r=e[0],n=e[1];switch(t){case 0:return[1,r,n];case 1:return[-r,1,n];case 2:return[-r,-n,1];case 3:return[-1,-n,-r];case 4:return[n,-1,-r];case 5:return[n,r,-1];default:throw{error:\"Invalid face\"}}};var singleSTtoUV=function(t){return t>=.5?1/3*(4*t*t-1):1/3*(1-4*(1-t)*(1-t))};S2.STToUV=function(t){return[singleSTtoUV(t[0]),singleSTtoUV(t[1])]};var singleUVtoST=function(t){return t>=0?.5*Math.sqrt(1+3*t):1-.5*Math.sqrt(1-3*t)};S2.UVToST=function(t){return[singleUVtoST(t[0]),singleUVtoST(t[1])]},S2.STToIJ=function(t,e){var r=1<<e,n=function(t){var e=Math.floor(t*r);return Math.max(0,Math.min(r-1,e))};return[n(t[0]),n(t[1])]},S2.IJToST=function(t,e,r){var n=1<<e;return[(t[0]+r[0])/n,(t[1]+r[1])/n]};var rotateAndFlipQuadrant=function(t,e,r,n){if(0==n){1==r&&(e.x=t-1-e.x,e.y=t-1-e.y);var o=e.x;e.x=e.y,e.y=o}},pointToHilbertQuadList=function(t,e,r,n){var o={a:[[0,\"d\"],[1,\"a\"],[3,\"b\"],[2,\"a\"]],b:[[2,\"b\"],[1,\"b\"],[3,\"a\"],[0,\"c\"]],c:[[2,\"c\"],[3,\"d\"],[1,\"c\"],[0,\"b\"]],d:[[0,\"a\"],[3,\"c\"],[1,\"d\"],[2,\"d\"]]};\"number\"!=typeof n&&console.warn(new Error(\"called pointToHilbertQuadList without face value, defaulting to '0'\").stack);for(var a=n%2?\"d\":\"a\",S=[],i=r-1;i>=0;i--){var l=1<<i,u=t&l?1:0,s=e&l?1:0,c=o[a][2*u+s];S.push(c[0]),a=c[1]}return S};S2.S2Cell=function(){},S2.S2Cell.FromHilbertQuadKey=function(t){var e,r,n,o,a,S,i=t.split(\"/\"),l=parseInt(i[0]),u=i[1],s=u.length,c={x:0,y:0};for(e=s-1;e>=0;e--)r=s-e,n=u[e],o=0,a=0,\"1\"===n?a=1:\"2\"===n?(o=1,a=1):\"3\"===n&&(o=1),S=Math.pow(2,r-1),rotateAndFlipQuadrant(S,c,o,a),c.x+=S*o,c.y+=S*a;if(l%2===1){var g=c.x;c.x=c.y,c.y=g}return S2.S2Cell.FromFaceIJ(parseInt(l),[c.x,c.y],r)},S2.S2Cell.FromLatLng=function(t,e){if(!t.lat&&0!==t.lat||!t.lng&&0!==t.lng)throw new Error(\"Pass { lat: lat, lng: lng } to S2.S2Cell.FromLatLng\");var r=S2.LatLngToXYZ(t),n=S2.XYZToFaceUV(r),o=S2.UVToST(n[1]),a=S2.STToIJ(o,e);return S2.S2Cell.FromFaceIJ(n[0],a,e)},S2.S2Cell.FromFaceIJ=function(t,e,r){var n=new S2.S2Cell;return n.face=t,n.ij=e,n.level=r,n},S2.S2Cell.prototype.toString=function(){return\"F\"+this.face+\"ij[\"+this.ij[0]+\",\"+this.ij[1]+\"]@\"+this.level},S2.S2Cell.prototype.getLatLng=function(){var t=S2.IJToST(this.ij,this.level,[.5,.5]),e=S2.STToUV(t),r=S2.FaceUVToXYZ(this.face,e);return S2.XYZToLatLng(r)},S2.S2Cell.prototype.getCornerLatLngs=function(){for(var t=[],e=[[0,0],[0,1],[1,1],[1,0]],r=0;4>r;r++){var n=S2.IJToST(this.ij,this.level,e[r]),o=S2.STToUV(n),a=S2.FaceUVToXYZ(this.face,o);t.push(S2.XYZToLatLng(a))}return t},S2.S2Cell.prototype.getFaceAndQuads=function(){var t=pointToHilbertQuadList(this.ij[0],this.ij[1],this.level,this.face);return[this.face,t]},S2.S2Cell.prototype.toHilbertQuadkey=function(){var t=pointToHilbertQuadList(this.ij[0],this.ij[1],this.level,this.face);return this.face.toString(10)+\"/\"+t.join(\"\")},S2.latLngToNeighborKeys=S2.S2Cell.latLngToNeighborKeys=function(t,e,r){return S2.S2Cell.FromLatLng({lat:t,lng:e},r).getNeighbors().map(function(t){return t.toHilbertQuadkey()})},S2.S2Cell.prototype.getNeighbors=function(){var t=function(t,e,r){var n=1<<r;if(e[0]>=0&&e[1]>=0&&e[0]<n&&e[1]<n)return S2.S2Cell.FromFaceIJ(t,e,r);var o=S2.IJToST(e,r,[.5,.5]),a=S2.STToUV(o),S=S2.FaceUVToXYZ(t,a),i=S2.XYZToFaceUV(S);return t=i[0],a=i[1],o=S2.UVToST(a),e=S2.STToIJ(o,r),S2.S2Cell.FromFaceIJ(t,e,r)},e=this.face,r=this.ij[0],n=this.ij[1],o=this.level;return[t(e,[r-1,n],o),t(e,[r,n-1],o),t(e,[r+1,n],o),t(e,[r,n+1],o)]},S2.FACE_BITS=3,S2.MAX_LEVEL=30,S2.POS_BITS=2*S2.MAX_LEVEL+1,S2.facePosLevelToId=S2.S2Cell.facePosLevelToId=S2.fromFacePosLevel=function(t,e,r){var n,o,a,S=exports.dcodeIO&&exports.dcodeIO.Long||require(\"long\");for(r||(r=e.length),e.length>r&&(e=e.substr(0,r)),n=S.fromString(t.toString(10),!0,10).toString(2);n.length<S2.FACE_BITS;)n=\"0\"+n;for(o=S.fromString(e,!0,4).toString(2);o.length<2*r;)o=\"0\"+o;for(a=n+o,a+=\"1\";a.length<S2.FACE_BITS+S2.POS_BITS;)a+=\"0\";return S.fromString(a,!0,2).toString(10)},S2.keyToId=S2.S2Cell.keyToId=S2.toId=S2.toCellId=S2.fromKey=function(t){var e=t.split(\"/\");return S2.fromFacePosLevel(e[0],e[1],e[1].length)},S2.idToKey=S2.S2Cell.idToKey=S2.S2Cell.toKey=S2.toKey=S2.fromId=S2.fromCellId=S2.S2Cell.toHilbertQuadkey=S2.toHilbertQuadkey=function(t){for(var e=exports.dcodeIO&&exports.dcodeIO.Long||require(\"long\"),r=e.fromString(t,!0,10).toString(2);r.length<S2.FACE_BITS+S2.POS_BITS;)r=\"0\"+r;for(var n=r.lastIndexOf(\"1\"),o=r.substring(0,3),a=r.substring(3,n),S=a.length/2,i=e.fromString(o,!0,2).toString(10),l=e.fromString(a,!0,2).toString(4);l.length<S;)l=\"0\"+l;return i+\"/\"+l},S2.keyToLatLng=S2.S2Cell.keyToLatLng=function(t){var e=S2.S2Cell.FromHilbertQuadKey(t);return e.getLatLng()},S2.idToLatLng=S2.S2Cell.idToLatLng=function(t){var e=S2.idToKey(t);return S2.keyToLatLng(e)},S2.S2Cell.latLngToKey=S2.latLngToKey=S2.latLngToQuadkey=function(t,e,r){if(isNaN(r)||1>r||r>30)throw new Error(\"'level' is not a number between 1 and 30 (but it should be)\");return S2.S2Cell.FromLatLng({lat:t,lng:e},r).toHilbertQuadkey()},S2.stepKey=function(t,e){var r,n=exports.dcodeIO&&exports.dcodeIO.Long||require(\"long\"),o=t.split(\"/\"),a=o[0],S=o[1],i=o[1].length,l=n.fromString(S,!0,4);e>0?r=l.add(Math.abs(e)):0>e&&(r=l.subtract(Math.abs(e)));var u=r.toString(4);for(\"0\"===u&&console.warning(new Error(\"face/position wrapping is not yet supported\"));u.length<i;)u=\"0\"+u;return a+\"/\"+u},S2.S2Cell.prevKey=S2.prevKey=function(t){return S2.stepKey(t,-1)},S2.S2Cell.nextKey=S2.nextKey=function(t){return S2.stepKey(t,1)};";
document.head.appendChild(s2script);

var myscript = document.createElement('script');
myscript.textContent = "\
function getLatLngFromCenter(){\
    var lls = map.mapUrl.indexOf('ll=')+3;\
    var lle = map.mapUrl.indexOf('&', lls);\
    var ll = map.mapUrl.substring(lls, lle).split(',');\
    var lat = ll[0];\
    var lng = ll[1];\
    return { lat: lat, lng: lng };\
}\
function fillCell(corners){\
    for(var i=1; i<=7; i++){\
        var strokeColor = i==4?getColor('l15boundary'):getColor('l17boundary');\
        var strokeWeight = 1;\
        var strokeOpacity = i==4?0.75:i%2==0?0.5:0.25;\
        new google.maps.Polyline({path: [{lat: (1.0-0.125*i)*corners[0].lat+0.125*i*corners[1].lat, lng:(1.0-0.125*i)*corners[0].lng+0.125*i*corners[1].lng}, {lat: 0.125*i*corners[2].lat+(1.0-0.125*i)*corners[3].lat, lng:0.125*i*corners[2].lng+(1.0-0.125*i)*corners[3].lng}], strokeColor: strokeColor, strokeWeight: strokeWeight, strokeOpacity: strokeOpacity, map: map});\
        new google.maps.Polyline({path: [{lat: (1.0-0.125*i)*corners[1].lat+0.125*i*corners[2].lat, lng:(1.0-0.125*i)*corners[1].lng+0.125*i*corners[2].lng}, {lat: 0.125*i*corners[3].lat+(1.0-0.125*i)*corners[0].lat, lng:0.125*i*corners[3].lng+(1.0-0.125*i)*corners[0].lng}], strokeColor: strokeColor, strokeWeight: strokeWeight, strokeOpacity: strokeOpacity, map: map});\
    }\
}\
function drawCell(cell, fill = true, dashed = false){\
    var corners = cell.getCornerLatLngs();\
    if(dashed){\
        var lineSymbol = {path: 'M 0,-1 0,1', strokeOpacity: 1, strokeColor: getColor('l'+cell.level+'boundary'), scale: 4};\
        corners[4] = corners[0];\
        new google.maps.Polyline({path: corners, fillOpacity: 0.0, strokeOpacity: 0, icons: [{icon: lineSymbol, offset: '0', repeat: '20px'}], map: map});\
    }\
    else new google.maps.Polygon({path: corners, fillOpacity: 0.0, strokeColor: getColor('l'+cell.level+'boundary'), map: map});\
    if(fill) fillCell(corners);\
}\
function getColor(type){\
    if(map.mapTypeId == \"roadmap\" || map.mapTypeId == \"terrain\"){\
        if(type=='l12boundary') return '#666666';\
        if(type=='l14boundary') return '#444444';\
        if(type=='l15boundary') return '#FF0000';\
        if(type=='l17boundary') return '#000066';\
    }\
    else{\
        if(type=='l12boundary') return '#CCCCCC';\
        if(type=='l14boundary') return '#000000';\
        if(type=='l15boundary') return '#FF0000';\
        if(type=='l17boundary') return '#FFFF00';\
    }\
    return '#000000';\
}\
$( '#toppokemon' ).after( '<div id=\"s2l12load\" style=\"display: inline-block; font-size: 12px; font-weight: 700; margin-left: 17px;\"><a style=\"margin-left: 10px; cursor: pointer;\"><i class=\"fa fa-cube\" style=\"color: gray; font-size: 16px; margin-right: 8px;\"></i><span class=\"normsize\">L12 S2</span></a></div>' );\
$( '#toppokemon' ).after( '<div id=\"9s2load\" style=\"display: inline-block; font-size: 12px; font-weight: 700; margin-left: 17px;\"><a style=\"margin-left: 10px; cursor: pointer;\"><i class=\"fa fa-cubes\" style=\"color: darkgoldenrod; font-size: 14px; margin-right: 8px;\"></i><span class=\"normsize\">9x S2</span></a></div>' );\
$( '#toppokemon' ).after( '<div id=\"s2load\" style=\"display: inline-block; font-size: 12px; font-weight: 700; margin-left: 17px;\"><a style=\"margin-left: 10px; cursor: pointer;\"><i class=\"fa fa-cube\" style=\"color: darkgoldenrod; font-size: 16px; margin-right: 8px;\"></i><span class=\"normsize\">S2</span></a></div>' );\
$('#topbarcontent').delegate('#s2load a', 'click', function(e){\
    var level = 14;\
    var cell = S2.S2Cell.FromLatLng(getLatLngFromCenter(), level);\
    drawCell(cell);\
});\
$('#topbarcontent').delegate('#9s2load a', 'click', function(e){\
    var level = 14;\
    var cell = S2.S2Cell.FromLatLng(getLatLngFromCenter(), level);\
    drawCell(cell);\
    var neighbors = cell.getNeighbors();\
		for(var i=0; i<4; i++){\
        drawCell(neighbors[i]);\
        if(i==0){drawCell(neighbors[i].getNeighbors()[1]);drawCell(neighbors[i].getNeighbors()[3]);}\
        if(i==2){drawCell(neighbors[i].getNeighbors()[1]);drawCell(neighbors[i].getNeighbors()[3]);}\
    }\
});\
$('#topbarcontent').delegate('#s2l12load a', 'click', function(e){\
    var level = 12;\
    var cell = S2.S2Cell.FromLatLng(getLatLngFromCenter(), level);\
    drawCell(cell, false, true);\
});\
$('#map').append('<div style=\"z-index: 1000001; -moz-user-select: none;  line-height: 3px; position: absolute; left:50%; top:50%; margin-left: -2px; margin-top: -2px; background-color: red;\" id=\"mapcursor\">&nbsp;</div>');\
";
document.body.appendChild(myscript);