Conectamos mapas en línea al navegador en el teléfono inteligente. Parte 3 - OverpassTurbo

Convertimos el script creado previamente en una API para ver un mapa interactivo desde el sitio web OverpassTurbo.eu a través de la aplicación de navegación del teléfono inteligente.


Contenido:


1 - Introducción. Mapas ráster estándar
2 - Continuación. Escribir un rasterizador simple para mapas vectoriales
3 - Un caso especial. Conectamos la tarjeta OverpassTurbo


¿Qué es OverpassTurbo?


Entonces Existe una base de datos de mapas como OpenStreetMaps. Contiene todo: los mares, los contornos de los continentes, las montañas, los bosques, las carreteras, los edificios, los parques infantiles e incluso los obstáculos. Cada objeto tiene un nombre, coordenadas y propiedades. Por ejemplo, por la carretera, el material de revestimiento, por el edificio, el número de pisos, etc.


Entonces aquí. La mayoría de las tarjetas que se presentan en Internet hoy en día se generan sobre la base de esta base de datos en particular. Pero, ¿qué pasa si todas estas tarjetas preparadas no nos quedan bien? ¡Puedes hacer el tuyo! Bueno, o al menos complementar el existente, que es mucho más fácil.


Esto es lo que está haciendo OverpassTurbo.eu . Es un IDE en línea. Utilizándolo, puede consultar la base de datos OSM. Hacemos clic en el botón Inicio , la solicitud va a la base de datos y, después de un tiempo, los datos nos regresan. OverpassTurbo visualiza estos datos en forma de marcadores vectoriales y líneas ubicadas en la parte superior de la capa de fondo, un mapa de OpenSteerMap.org .


Como ejemplo de lo que puede hacer con OverpassTurbo, quiero mostrarle el script que más me gusta. Fue escrito por un usuario bajo el apodo de Erelen. Entonces: este script dibuja en el mapa varias fuentes de agua potable y su nombre. En mi opinión, es muy útil y muy claro. Para ver cómo funciona este script, solo siga el enlace y haga clic en Iniciar . (Si el sitio da un error, vaya a través de la VPN e intente nuevamente)


https://overpass-turbo.eu/s/z95



O aquí hay un script que ya hice para mis propias necesidades. Con él, puede encontrar fácilmente buenas rutas para correr en parques desconocidos. Para hacer esto, el guión resalta caminos de grava bien arreglados: es el más conveniente para recorrerlos, para mi gusto. El asfalto está marcado en blanco. Senderos de tierra ordinarios en negro. Pero todos los caminos con la etiqueta "difícil de alcanzar" o "mala calidad de recubrimiento" estarán marcados con una línea discontinua discreta: para tropezar con menos frecuencia, trato de evitarlos. En general, el mapa está hecho para que pueda obtener direcciones a lo largo de las líneas más llamativas. Y para que al final esta ruta sea exitosa.


http://overpass-turbo.eu/s/KXU



De hecho, con esta herramienta puede complementar el mapa con los datos que desee. Y, noto que esto es muy, muy emocionante. Pero este artículo no se trata de eso. Si está interesado en este tema, puede familiarizarse con los conceptos básicos de Overpass aquí .


Pero antes de pasar al código, echemos un vistazo al resultado final que deberíamos obtener.


Instrucciones para los usuarios: cómo usar nuestra API


Entonces Supongamos que ya tiene un script listo para OverpassTurbo, cuyos resultados desea ver en su teléfono inteligente. Y no en el navegador, sino en el navegador. Para hacer esto, lleve su script al siguiente formato.


[bbox:{{bbox}}]; ( //     node[amenity=waste_basket]; ); out;>;out skel qt; 

En particular, estamos interesados ​​en la primera línea: nuestra aplicación la reemplazará.


Después de eso, haga clic en el botón Compartir . Asegúrese de desmarcar el estado Activar del cuadro de mapa mostrado .



Después de eso, copie el enlace. Por ejemplo, asumimos que su enlace copiado se ve así:


http://overpass-turbo.eu/s/KEy


Ahora mira nuestra API


https://anygis.herokuapp.com/mapshoter/overpass/{x}/{y}/{z}/{crossZoom}?script={script}


Con {x}, {y} y {z}, todo parece estar claro: estas son las coordenadas del mosaico deseado.


En lugar de {script} , debe sustituir la ID de su script. En nuestro ejemplo, s / Key .


Pero, ¿qué es {crossZoom} ? Supongamos que tiene 15. Luego, si solicita un mosaico para un zoom de menos de 15, el servidor no realizará una solicitud lenta para OverpassTurbo, sino que simplemente lo redirigirá al mapa con una capa de fondo vacía de OpenStreetMaps (que se cargará casi al instante). Este enfoque es necesario para que, si es necesario, pueda alejar el mapa, desplazarse rápidamente al lugar de interés, acercar y esperar. Espere hasta que OverpassTurbo genere un mapa con los resultados.


Espero que el principio básico sea claro. Ahora mire la URL completa para nuestra solicitud. Creo que ahora usar nuestra API no será difícil para usted: simplemente reemplace s / KEy con la ID de su script.


https://anygis.herokuapp.com/mapshoter/overpass/{x}/{y}/{z}/15?script=s/KEy


Y, mientras tanto, veremos cómo implementar dicha aplicación.


Escenario 3 - Buscar usando la URL y el caché del navegador


Entonces Comencemos con el archivo router.js . Hagamos que nuestro método acepte crossZoom y parámetros de script . Y luego los pasamos al trabajador. También agregamos una opción que interrumpirá el script y redirigirá al usuario a otro sitio si el zoom solicitado es demasiado bajo.


 const express = require( 'express' ) const PORT = process.env.PORT || 5000 const app = express() app.listen( PORT, () => { console.log( '    ', PORT ) }) const { StaticPool } = require( 'node-worker-threads-pool' ) const worker = "./worker.js" const workersPool = new StaticPool({ size: 3, task: worker, workerData: "no" }) //     app.get( '/:x/:y/:z/:crossZoom', async ( req, res, next ) => { const x = req.params.x const y = req.params.y const z = req.params.z const crossZoom = req.params.crossZoom const scriptName = req.query.script //     if ( Number( z ) < Number( crossZoom ) ) { res.redirect( `http://tile.openstreetmap.org/${z}/${x}/${y}.png` ) } //      const screenshot = await workersPool.exec( { x, y, z, scriptName } ) const imageBuffer = Buffer.from( screenshot, 'base64' ) res.writeHead( 200, { 'Content-Type': 'image/png', 'Content-Length': imageBuffer.length }) res.end( imageBuffer ) }) 

El archivo worker.js no ha cambiado mucho. Simplemente reenvíe las nuevas variables aún más.


 const { parentPort, workerData } = require( 'worker_threads' ); const puppeteer = require( 'puppeteer' ) const mapshoter = require( './mapshoter' ) var browser = "empty" parentPort.on( "message", ( params ) => { doMyAsyncCode( params ) .then( ( result ) => { parentPort.postMessage( result ) }) }) async function doMyAsyncCode( params ) { await prepareEnviroment() //   const screenshot = await mapshoter.makeTile( params.x, params.y, params.z, params.scriptName, browser ) return screenshot } async function prepareEnviroment( ) { if ( browser === "empty" ) { const herokuDeploymentParams = {'args' : ['--no-sandbox', '--disable-setuid-sandbox']} browser = await puppeteer.launch( herokuDeploymentParams ) } } 

Ahora echemos un vistazo a mapshoter.js . Primero, mira el código:


 const puppeteer = require( 'puppeteer' ) const geoTools = require( './geoTools' ) async function makeTile( x, y, z, scriptName, browserLink ) { //      const runButtonSelector = '#navs > div > div.buttons > div:nth-child(1) > a:nth-child(1)' const codeEditorSelector = '#editor > div.CodeMirror.CodeMirror-wrap > div:nth-child(1) > textarea' //          const coordinates = geoTools.getAllCoordinates( x, y, z ) const bBox = `[bbox:${coordinates.bBox.latMin}, ${coordinates.bBox.lonMin}, ${coordinates.bBox.latMax}, ${coordinates.bBox.lonMax}];` const centerCoordinates = `${coordinates.center.lat};${coordinates.center.lon};${z}` //      const browser = await browserLink const page = await browser.newPage() await page.setViewport( { width: 850, height: 450 } ) //  ,   : //      await page.waitFor( randomInt( 0, 500 ) ) //        URL var pageUrl = `http://overpass-turbo.eu/?C=${centerCoordinates}` await page.goto( pageUrl, { waitUntil: 'networkidle2', timeout: 10000 } ) //       URL pageUrl = 'http://overpass-turbo.eu/' + scriptName await page.goto( pageUrl, { waitUntil: 'networkidle0', timeout: 20000 } ) //      await page.focus( codeEditorSelector ) //        , //     await page.keyboard.type( bBox + ' //' ) // ,  -IDE   await page.waitFor( 100 ) //     - await page.click( runButtonSelector ) // ,      . //     . await page.waitForFunction(() => !document.querySelector('body > div.modal > div > ul > li:nth-child(1)'), {polling: 'mutation'}); await page.waitFor( 1000 ) //    const cropOptions = { fullPage: false, clip: { x: 489, y: 123, width: 256, height: 256 } } const screenshot = await page.screenshot( cropOptions ) //   await page.close() return screenshot } //       function randomInt( low, high ) { return Math.floor( Math.random() * ( high - low ) + low ) } module.exports.makeTile = makeTile 

Para comenzar, en este script, por el bien de la variedad, trabajaremos con selectores de elementos ordinarios (que no son XPath ). Cómo encontrarlos se describió en un artículo anterior .


A continuación obtenemos las coordenadas. Solo que esta vez, además de las coordenadas del centro, también se necesitan las coordenadas de los bordes del mosaico ( bBox ).


A continuación, inicie el navegador. Todo es típico aquí. Pero antes de pasar a cargar la página, deje que el script espere una cantidad aleatoria de tiempo de 0 a 500 ms. Para que no recibamos demasiadas solicitudes idénticas al mismo tiempo y no se nos prohíba.


Después de eso, vamos al sitio en la URL a la que se agregan las coordenadas del centro del mosaico. Como resultado, el lugar deseado está en el centro del mapa.


Después de eso, vaya a otra URL. Esta vez con la identificación de nuestro script. Como resultado, nuestro script aparecerá en el texto del editor de código.


(Tenga en cuenta que si en el menú Compartir al copiar la URL de nuestro script no desmarquemos la casilla de verificación Guardar estado del mapa, el mapa se desplazará. Y no necesitamos esto en absoluto)


Y ahora responderé razonablemente a la pregunta: ¿por qué vamos a la URL dos veces, es decir, gastamos dos veces en cargar este sitio? Yo respondo Porque, en primer lugar, no pude encontrar cómo combinar la carga del script y la transición a las coordenadas especificadas en una solicitud de URL. En segundo lugar, porque por alguna razón Puppeteer imprime el texto extremadamente lento y trabaja con los elementos de la interfaz en este sitio. ¡Se puede imprimir un minuto y medio! Entonces, la idea de insertar las coordenadas en el campo de búsqueda y luego hacer clic en los botones de zoom, como hicimos en el artículo anterior, se decidió rechazar. Como resultado, hacer doble clic en el enlace resultó mucho más rápido que hacer todo esto. Quizás esto sea un error y se solucionará tarde o temprano, pero por ahora estamos trabajando con lo que es.


Por desgracia, no podrás dejar completamente la entrada de texto. Tendremos que reemplazar la primera línea en la ventana del editor de código. Por el momento, informa que es necesario descargar información de la base de datos para todo el territorio que se encuentra actualmente en la pantalla.


 [bbox:{{bbox}}]; 

Lo reemplazaremos con las coordenadas de los bordes del mosaico. Esto es para no perder demasiado tiempo descargando de la base de datos. Entonces el guión imprime en la primera línea algo así como este texto:


 [bbox:55.6279, 37.5622, 55.6341, 37.5732]; // 

Y para no tener que borrar la línea original (muchas veces presionando lentamente Eliminar para esto), simplemente comentamos al respecto. Por lo tanto, reduciremos tanto como sea posible el tiempo dedicado a ingresar texto y el tiempo de carga de la base de datos. Como resultado, la primera línea se verá así:


 [bbox:55.6279, 37.5622, 55.6341, 37.5732]; //[bbox:{{bbox}}]; 

Después de eso, nuestro script debe hacer clic en el botón Inicio , esperar un poco, tomar una captura de pantalla del mapa y enviárselo al usuario. Y todo: ¡la tarea está completa!


Si desea ver un ejemplo del script resultante, puede hacer clic en este enlace .


Conclusión


Bueno, como no es difícil de suponer, esta versión del script funcionará incluso más lentamente que las anteriores. Después de todo, ahora el sitio dedica tiempo a una solicitud de una base de datos de terceros. Y por sí solo, no funciona demasiado rápido. Sin embargo, este método hace que sea extremadamente fácil (aunque lento) obtener una tarjeta única y personalizada. Y, además, basado en los últimos datos. Y esto, a veces, puede ser muy útil. Por lo tanto, vale la pena tener este método en mente.


Y eso es todo. Por si acaso, le recuerdo que en mi sitio web AnyGIS hay un archivo de ajustes preestablecidos para navegadores Locus, OsmAnd y GuruMaps. Existen tanto mapas ráster como mapas vectoriales "rasterizados", para ver qué aplicación se utiliza en estos artículos. Ven y usa.

Source: https://habr.com/ru/post/461073/


All Articles