function makeOSMTiles(geo) { if (geo["latitude"] !== undefined && geo["longitude"] !== undefined && geo["latitude"] >= -90 && geo["latitude"] <= 90 && geo["longitude"] >= -180 && geo["longitude"] <= 180) { var tileServer = "https://c.tile.openstreetmap.org", currentVersion = 0, getTile = function(zoom, x, y, result) { return new Promise(function(resolve, reject) { var img = new Image(); img.addEventListener("load", function() { result.img = img; resolve(result); }); img.addEventListener("error", function() { console.warn("Error loading tile ", { "zoom":zoom, "x": x, "y": y }); reject(img); }); img.crossOrigin = "anonymous"; img.src = tileServer + '/' +zoom +'/' +x +'/' +y +'.png'; }); }, canvas = document.createElement("canvas"), mapCanvas = document.createElement("canvas"); var imgSize = 300, tileSize = imgSize /3; canvas.height = canvas.width = mapCanvas.height = mapCanvas.width = imgSize; var ctx = canvas.getContext("2d"), mapCtx = mapCanvas.getContext("2d"); var drawPlot = function(centerX, centerY, radius) { centerX = tileSize *centerX +tileSize; centerY = tileSize *centerY +tileSize; ctx.putImageData(mapCtx.getImageData(0, 0, imgSize, imgSize), 0, 0); if (radius !== undefined) { ctx.beginPath(); ctx.arc(centerX, centerY, Math.max(radius, 10), 0, 2 * Math.PI, false); ctx.lineWidth = 2; ctx.fillStyle = 'rgba(244, 146, 66, 0.4)'; ctx.strokeStyle = 'rgba(244, 146, 66, 0.8)'; ctx.stroke(); ctx.fill(); } if (radius === undefined || radius > 25) { ctx.strokeStyle = 'rgba(244, 146, 66, 1)'; ctx.beginPath(); ctx.moveTo(centerX -5, centerY -5); ctx.lineTo(centerX +5, centerY +5); ctx.stroke(); ctx.moveTo(centerX +5, centerY -5); ctx.lineTo(centerX -5, centerY +5); ctx.stroke(); } }, distanceLatlonlon = function(lat, lon0, lon1) { lat = lat * Math.PI / 180; lon0 = lon0 *Math.PI / 180; lon1 = lon1 *Math.PI / 180; return Math.abs(6371e3 * Math.acos(Math.pow(Math.sin(lat), 2) +Math.pow(Math.cos(lat), 2) *Math.cos(lon1 -lon0))); }, drawTiles = function(zoom, lat, lon, acc) { mapCtx.fillStyle = "#808080"; mapCtx.fillRect(0, 0, imgSize, imgSize); ctx.fillStyle = "#808080"; ctx.fillRect(0, 0, imgSize, imgSize); var nbTiles = Math.pow(2, zoom), px = ((lon +180) / 360) * nbTiles, py = (1 -Math.log(Math.tan(lat *Math.PI / 180) + 1 / Math.cos(lat * Math.PI / 180))/Math.PI) / 2 *nbTiles, absoluteX = Math.floor(px), absoluteY = Math.floor(py), accRadiusPx = acc ? acc * 100 /distanceLatlonlon(180/Math.PI*Math.atan(0.5*(Math.exp(Math.PI-2*Math.PI*absoluteY/nbTiles)-Math.exp(-(Math.PI-2*Math.PI*absoluteY/nbTiles)))), absoluteX / nbTiles * 360.0 - 180.0, (absoluteX +1) / nbTiles * 360.0 - 180.0) : 0, v = currentVersion; for (var i =0; i < 3; i++) for (var j =0; j < 3; j++) getTile(zoom, absoluteX +i -1, absoluteY +j -1, { i: i, j: j, v: v }).then(function(img) { if (img.v === currentVersion) { mapCtx.drawImage(img.img, tileSize *img.i, tileSize *img.j, tileSize, tileSize); drawPlot(px -absoluteX, py -absoluteY, accRadiusPx); } }); }, currentZoom, setZoom = function(val) { var newZoom = Math.max(4, Math.min(19, val)); if (currentZoom !== newZoom) { currentVersion++; currentZoom = newZoom; drawTiles(currentZoom, Number(geo["latitude"]), Number(geo["longitude"]), Number(geo["accuracy"])); } }; setZoom(12); var canvasWrapper = document.createElement("div"), buttonContainer = document.createElement("div"), zoomP = document.createElement("button"), zoomM = document.createElement("button"); canvasWrapper.className = R.klass.map.container; canvas.className = R.klass.map.canvas; buttonContainer.className = R.klass.map.buttonContainer; zoomM.className = R.klass.map.buttonM; zoomP.className = R.klass.map.buttonP; zoomM.addEventListener("click", function() { setZoom(currentZoom -1); }); zoomP.addEventListener("click", function() { setZoom(currentZoom +1); }); buttonContainer.appendChild(zoomM); buttonContainer.appendChild(zoomP); canvasWrapper.appendChild(canvas); canvasWrapper.appendChild(buttonContainer); return canvasWrapper; } }