Wir verbinden Online-Karten mit dem Navigator auf dem Smartphone. Teil 2 - Vektorkarten

Wir schreiben eine Serveranwendung, die PNG-Rasterkacheln basierend auf Online-Vektorkarten generiert. Verwenden Sie Web Scraping mit Puppeteer, um Kartendaten abzurufen.


Inhalt:


1 - Einführung. Standard-Rasterkarten
2 - Fortsetzung. Schreiben eines einfachen Rasters für Vektorkarten
3 - Ein Sonderfall. Wir verbinden die OverpassTurbo-Karte


Fortsetzung


Und so kamen wir zum interessantesten Thema. Stellen Sie sich vor, wir haben eine Site mit einer Karte gefunden, die wir unserem Navigator wirklich hinzufügen möchten. Wir machen alles in Übereinstimmung mit den Anweisungen aus dem vorherigen Teil . Wir öffnen die Anzeige der Inhalte der Website und es gibt keine Bilder! Absolut. Nun, ein paar Symbole und das wars. Und eine andere Textdatei mit einer Liste von Koordinaten.


Herzlichen Glückwunsch, wir haben eine Vektorkarte gefunden. Grob gesagt wird es von Ihrem Browser in Echtzeit gerendert. Sie braucht also überhaupt keine vorbereiteten Fliesen. Einerseits gibt es bisher nicht so viele Vektorkarten. Diese Technologie ist jedoch sehr vielversprechend und kann im Laufe der Zeit um ein Vielfaches erweitert werden. Nun, wir haben es herausgefunden. Und doch, was machen wir jetzt?


Zunächst können Sie versuchen, einen Browser einer sehr, sehr alten Version herunterzuladen. Eine, die die zum Rendern der Karte erforderlichen Funktionen nicht unterstützt. Möglicherweise wird Ihnen eine andere Version der Site angezeigt. Mit Rasterkarte. Nun, was Sie damit machen müssen, wissen Sie bereits.


Wenn dieser Trick jedoch nicht funktioniert hat, Sie diese Karte aber dennoch wirklich erhalten möchten und darüber hinaus nicht im Browser des Smartphones, nämlich in Ihrem Navigator, gibt es einen Weg.


Hauptidee


Wir gehen davon aus, dass wir eine Karte erhalten möchten, die in jedem der Navigatoren geöffnet werden kann. Dann brauchen wir einen Adapter - eine Art Vermittler, der für uns Kacheln im PNG-Format generiert.


Es stellt sich heraus, dass Sie brauchen ein Fahrrad erfinden Entwicklung einer weiteren Engine zur Visualisierung von Vektordaten. Nun, oder Sie können ein Skript schreiben, das zur Site geht und es seine eigene Vektorkarte selbst zeichnen lässt. Und dann wartet er auf den Download, macht einen Screenshot, schneidet ihn ab und kehrt zum Benutzer zurück. Vielleicht werde ich die zweite Option wählen.


Um Screenshots zu machen, verwende ich einen "Fernbedienungsbrowser" - Headless Chrome. Sie können es mit dem Knoten js library Puppeteer steuern. In diesem Artikel erfahren Sie mehr über die Grundlagen der Arbeit mit dieser Bibliothek.


Hallo Welt! Oder erstellen und passen Sie ein Projekt an


Wenn Sie Node.js noch nicht installiert haben, gehen Sie zu dieser oder dieser Seite, wählen Sie Ihr Betriebssystem aus und schließen Sie die Installation gemäß den Anweisungen ab.


Erstellen Sie einen neuen Ordner für das Projekt und öffnen Sie ihn im Terminal.


$ cd /Mapshoter_habr 

Wir beginnen mit dem Manager für die Erstellung eines neuen Projekts


 $ npm init 

Hier können Sie den Namen des Projekts ( Paketname ), den Namen der Datei für die Eingabe der Anwendung ( Einstiegspunkt ) und den Namen des Autors ( Autors ) angeben. Für alle anderen Anfragen stimmen wir den Standardparametern zu: Wir geben nichts ein und drücken einfach die Eingabetaste . Am Ende drücken Sie y und die Eingabetaste .


Installieren Sie als Nächstes die erforderlichen Frameworks für die Arbeit. Express zum Erstellen eines Servers und Puppenspieler zum Arbeiten mit einem Browser.


 $ npm install express $ npm i puppeteer 

Infolgedessen wird die Projektkonfigurationsdatei package.json im Projektordner angezeigt. In meinem Fall ist dies:


 { "name": "mapshoter_habr", "version": "1.0.0", "description": "", "main": "router.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "nnngrach", "license": "ISC", "dependencies": { "express": "^4.17.1", "puppeteer": "^1.18.1" } } 

Ich werde die Startzeile zum Abschnitt "Skripte" hinzufügen, um unsere Anwendung bequemer zu starten.


 "scripts": { "start": "node router.js", "test": "echo \"Error: no test specified\" && exit 1" }, 

Erstellen Sie nun zwei Dateien mit der Implementierung der Grundfunktionalität. Die erste Datei ist der Einstiegspunkt in die Anwendung. In meinem Fall router.js . Er wird einen Server erstellen und das Routing durchführen.


 //        const express = require( 'express' ) const mapshoter = require( './mapshoter' ) //  ,       const PORT = process.env.PORT || 5000 //     const app = express() app.listen( PORT, () => { console.log( '    ', PORT ) }) //       // http://siteName.com/x/y/z app.get( '/:x/:y/:z', async ( req, res, next ) => { //      const x = req.params.x const y = req.params.y const z = req.params.z //      const screenshot = await mapshoter.makeTile( x, y, z ) //        const imageBuffer = Buffer.from( screenshot, 'base64' ) //    res.writeHead( 200, { 'Content-Type': 'image/png', 'Content-Length': imageBuffer.length }) //    res.end( imageBuffer ) }) 

Erstellen Sie nun eine zweite Datei. Er wird den Browser steuern und Screenshots machen. Ich habe es mapshoter.js genannt .


 const puppeteer = require( 'puppeteer' ) async function makeTile( x, y, z ) { //   const browser = await puppeteer.launch() //       const page = await browser.newPage() await page.goto( 'https://www.google.ru/' ) //    const screenshot = await page.screenshot() //      await browser.close() return screenshot } module.exports.makeTile = makeTile 

Führen Sie unser Skript aus und überprüfen Sie die Leistung. Geben Sie dazu die Konsole ein:


$ npm start


Es wird eine Meldung angezeigt, die besagt, dass der Server auf Port 5000 erstellt wurde. Öffnen Sie nun einen Browser auf Ihrem Computer und rufen Sie die lokale Adresse unseres Servers auf. Anstelle der x-, y- und z- Koordinaten können Sie beliebige Zahlen eingeben. Ich habe 1, 2, 3 eingegeben.


http://localhost:5000/1/2/3


Wenn alles richtig gemacht wurde, wird ein Screenshot der Google-Website angezeigt.


Bild


Drücken Sie Strg + C in der Konsole, um unser Skript zu stoppen.


Herzlichen Glückwunsch, die Basis unserer Bewerbung ist fertig! Wir haben einen Server erstellt, der unsere HTML-Anfragen akzeptiert, einen Screenshot macht und ein Bild an uns zurückgibt. Jetzt ist es Zeit, mit der Implementierung der Details fortzufahren.


Berechnen Sie die Koordinaten


Die Idee ist, dass der Browser eine Site mit einer Karte öffnet und die Koordinaten des gewünschten Ortes in die Suchleiste eingibt. Nachdem Sie auf die Schaltfläche "Suchen" geklickt haben, befindet sich dieser Ort genau in der Mitte des Bildschirms. So wird es einfach sein, den Bereich auszuschneiden, den wir brauchen.


Aber zuerst müssen Sie die Koordinaten der Mitte der Kachel anhand ihrer Seriennummer berechnen. Ich werde dies basierend auf der Formel zum Finden der oberen linken Ecke tun. Ich habe es in die Funktion getCoordinates () eingefügt .


Und da für einige Websites neben der Mitte der Kachel auch die Ränder angegeben werden müssen, werde ich auch nach ihnen suchen. Nun, erstellen wir ein separates Modul für diese Berechnungen unter dem Namen geoTools.js . Hier ist sein Code:


 //   -   function getCoordinates( x, y, z ) { const n = Math.pow( 2, z ) const lon = x / n * 360.0 - 180.0 const lat = 180.0 * ( Math.atan( Math.sinh( Math.PI * ( 1 - 2 * y / n) ) ) ) / Math.PI return { lat: lat, lon: lon } } //          function getCenter( left, rigth, top, bottom ) { let lat = ( left + rigth ) / 2 let lon = ( top + bottom ) / 2 return { lat: lat, lon: lon } } //        function getAllCoordinates( stringX, stringY, stringZ ) { //      const x = Number( stringX ) const y = Number( stringY ) const z = Number( stringZ ) //     //    -  -  const topLeft = getCoordinates( x, y, z ) const bottomRight = getCoordinates( x+1, y+1, z ) //   const center = getCenter( topLeft.lat, bottomRight.lat, topLeft.lon, bottomRight.lon ) //   const bBox = { latMin: bottomRight.lat, lonMin: topLeft.lon, latMax: topLeft.lat, lonMax: bottomRight.lon } return { bBox: bBox, center: center } } module.exports.getAllCoordinates = getAllCoordinates 

Jetzt können wir mit der Implementierung des Skripts für die Arbeit mit dem Browser beginnen. Schauen wir uns einige Szenarien an, wie dies getan werden kann.


Szenario 1 - API-Suche


Beginnen wir mit dem einfachsten Fall, in dem Sie einfach die Koordinaten in die URL der Kartenseite eingeben können. Zum Beispiel so:


https://nakarte.me/#m=5/50.28144/89.30666&l=O/Wp


Schauen wir uns das Skript an. Ersetzen Sie einfach, löschen Sie den gesamten Inhalt der Datei mapshoter.js und fügen Sie den folgenden Code ein.


In dieser Version geben wir beim Starten des Browsers zusätzliche Parameter an, mit denen er auf Linux-Servern wie Heroku gestartet und ausgeführt werden kann. Auch jetzt werden wir die Größe des Fensters reduzieren, damit so wenig Kartenkacheln wie möglich auf den Bildschirm passen. Dadurch erhöhen wir die Ladegeschwindigkeit der Seite.


Als nächstes berechnen wir die Koordinaten der Mitte der gewünschten Kachel. Wir fügen sie in die URL ein und klicken darauf. Die Kachel wird genau in der Mitte des Bildschirms angezeigt. Schneiden Sie ein Stück mit 256 x 256 Pixel. Dies wird die Kachel sein, die wir brauchen. Es bleibt nur, um es an den Benutzer zurückzugeben.


Bevor ich zum Code übergehe, stelle ich fest, dass aus Gründen der Übersichtlichkeit alle Fehlerbehandlungen aus dem Skript entfernt wurden.


 const puppeteer = require( 'puppeteer' ) const geoTools = require( './geoTools' ) async function makeTile( x, y, z ) { //    ,    Heroku const herokuDeploymentParams = {'args' : ['--no-sandbox', '--disable-setuid-sandbox']} const browser = await puppeteer.launch( herokuDeploymentParams ) //        //       const page = await browser.newPage() await page.setViewport( { width: 660, height: 400 } ) //         URL const coordinates = geoTools.getAllCoordinates( x, y, z ) const centerCoordinates = `${z}/${coordinates.center.lat}/${coordinates.center.lon}&l=` const pageUrl = 'https://nakarte.me/#m=' + centerCoordinates + "O/Wp" //   URL  ,    await page.goto( pageUrl, { waitUntil: 'networkidle0', timeout: 20000 } ) //    const cropOptions = { fullPage: false, clip: { x: 202, y: 67, width: 256, height: 256 } } const screenshot = await page.screenshot( cropOptions ) //      await browser.close() return screenshot } module.exports.makeTile = makeTile 

Führen Sie nun unser Skript aus und sehen Sie sich die Karte für diesen Abschnitt an.


http://localhost:5000/24/10/5


Wenn alles richtig gemacht wurde, sollte der Server eine solche Kachel zurückgeben:



Vergleichen Sie unsere Kachel mit dem Original von OpenStreetMaps.org, um sicherzustellen, dass wir beim Zuschneiden nichts verwechseln



Szenario 2 - Suche über die Site-Oberfläche


Es ist jedoch nicht immer möglich, eine Karte über eine Browserzeile zu steuern. In solchen Fällen verhält sich unser Skript wie ein lebender Benutzer. Er druckt die Koordinaten in das Suchfeld und klickt auf die Schaltfläche Suchen. Danach entfernt er die Markierung des gefundenen Punktes, die normalerweise in der Mitte des Bildschirms angezeigt wird. Und dann klickt er auf die Schaltflächen, um die Skala zu vergrößern oder zu verkleinern, bis er die gewünschte erreicht hat. Dann wird ein Screenshot erstellt und an den Benutzer zurückgegeben.


Ich stelle fest, dass normalerweise nach der Suche derselbe Maßstab eingestellt wird. 15. zum Beispiel. In unserem Beispiel ist dies nicht immer der Fall. Daher erkennen wir die Zoomstufe an den Parametern der HTML-Elemente auf der Seite.


Auch in diesem Beispiel werden wir mithilfe von XPath-Selektoren nach Schnittstellenelementen suchen. Aber wie erkennt man sie?


Öffnen Sie dazu die gewünschte Seite im Browser und öffnen Sie die Entwickler-Symbolleiste ( Ctll + Alt + I für Google Chrome). Drücken Sie die Taste, um Elemente auszuwählen. Wir klicken auf das Element, das Sie interessiert (ich habe auf das Suchfeld geklickt).



Die Liste der Elemente scrollt zu der Liste, auf die Sie geklickt haben, und wird blau hervorgehoben. Klicken Sie auf die Schaltfläche mit drei Punkten links neben dem Namen.


Wählen Sie im Popup-Menü die Option Kopieren. Wenn Sie als Nächstes eine reguläre Auswahl benötigen, klicken Sie auf Auswahl kopieren . Für dasselbe Beispiel verwenden wir jedoch das Element XPath kopieren .



Ersetzen Sie nun den Inhalt der Datei mapshoter.js durch diesen Code. Darin habe ich bereits Selektoren für alle notwendigen Schnittstellenelemente gesammelt.


 const puppeteer = require( 'puppeteer' ) const geoTools = require( './geoTools' ) async function makeTile( x, y, z ) { //      const searchFieldXPath = '//*[@id="map"]/div[1]/div[1]/div/input' const zoomPlusXPath = '//*[@id="map"]/div[2]/div[2]/div[4]/div[1]/a[1]' const zoomMinusXPath = '//*[@id="map"]/div[2]/div[2]/div[4]/div[1]/a[2]' const directionButonXPath = '//*[@id="gtm-poi-card-get-directions"]' const deletePinButonXPatch = '//*[@id="map"]/div[1]/div/div/div[1]/div[2]/div/div[4]/div/div[4]' //         () const coordinates = geoTools.getAllCoordinates( x, y, z ) const centerCoordinates = `lat=${coordinates.center.lat} lng=${coordinates.center.lon}` //      const herokuDeploymentParams = {'args' : ['--no-sandbox', '--disable-setuid-sandbox']} const browser = await puppeteer.launch( herokuDeploymentParams ) const page = await browser.newPage() await page.setViewport( { width: 1100, height: 450 } ) //         const pageUrl = 'https://www.waze.com/en/livemap?utm_campaign=waze_website' await page.goto( pageUrl, { waitUntil: 'networkidle2', timeout: 10000 } ) //    ,      await click( searchFieldXPath, page ) //        await page.keyboard.type( centerCoordinates ) //  Enter    page.keyboard.press( 'Enter' ); //  500     await page.waitFor( 500 ) //       //       await click( directionButonXPath, page ) await page.waitFor( 100 ) await click( deletePinButonXPatch, page ) await page.waitFor( 100 ) //       //        while( z > await fetchCurrentZoom( page )) { await click( zoomPlusXPath, page ) await page.waitFor( 300 ) } while( z < await fetchCurrentZoom( page )) { await click( zoomMinusXPath, page ) await page.waitFor( 300 ) } //    const cropOptions = { fullPage: false, clip: { x: 422, y: 97, width: 256, height: 256 } } const screenshot = await page.screenshot( cropOptions ) //   await browser.close() return screenshot } //  : //        async function click( xPathSelector, page ) { await page.waitForXPath( xPathSelector ) const foundedElements = await page.$x( xPathSelector ) if ( foundedElements.length > 0 ) { await foundedElements[0].click() } else { throw new Error( "XPath element not found: ", xPathSelector ) } } //         html  async function fetchCurrentZoom( page ) { const xPathSelector = '//*[@id="map"]/div[2]' await page.waitForXPath( xPathSelector ) const elems = await page.$x(xPathSelector) const elementParams = await page.evaluate((...elems) => { return elems.map(e => e.className); }, ...elems); const zoom = elementParams[0].split('--zoom-').pop() return zoom } module.exports.makeTile = makeTile 

Führen Sie unser Skript aus und folgen Sie dem Link. Wenn alles richtig gemacht wurde, wird das Skript uns so etwas wie diese Kachel zurückgeben.


http://localhost:5000/1237/640/11



Optimierung


Im Prinzip reichen die beiden oben beschriebenen Methoden aus, um mit Vektorkarten eine Verbindung zu vielen Standorten herzustellen. Wenn Sie jedoch plötzlich Zugriff auf eine neue Karte benötigen, müssen Sie das Skript in der Datei mapshoter.js nur geringfügig ändern. Das heißt, diese Methode macht es sehr einfach, neue Karten hinzuzufügen. Dies liegt an seinen Vorteilen.


Es gibt aber auch Nachteile. Und das wichtigste ist die Arbeitsgeschwindigkeit. Einfach vergleichen. Im Durchschnitt dauert das Herunterladen einer normalen Rasterkachel etwa 0,5 Sekunden. Der Empfang einer Kachel aus unserem Skript dauert derzeit ca. 8 Sekunden.


Aber das ist noch nicht alles! Wir verwenden Single-Threaded-Knoten js und unsere langen Anforderungen blockieren schließlich den Haupt-Thread, der von außen wie eine reguläre synchrone Warteschlange aussieht. Wenn wir versuchen, die Karte für den gesamten Bildschirm herunterzuladen (auf dem beispielsweise 24 Kacheln platziert sind), besteht die Gefahr, dass ein Problem auftritt.


Und noch etwas. Einige Navigatoren haben eine Zeitüberschreitung: Sie werden nach 30 Sekunden nicht mehr geladen. Dies bedeutet, dass mit der aktuellen Implementierung nur 3-4 Kacheln Zeit zum Laden haben. Mal sehen, was wir dagegen tun können.


Der wahrscheinlich naheliegendste Weg ist, einfach die Anzahl der Server zu erhöhen, auf denen unser Skript ausgeführt wird. Wenn wir beispielsweise 10 Server haben, haben diese Zeit, die Kacheln für den gesamten Bildschirm in 30 Sekunden zu verarbeiten. (Wenn Sie nicht viel Geld bezahlen möchten, können Sie es erhalten, indem Sie mehrere kostenlose Konten bei Heroku registrieren.)


Zweitens ist es weiterhin möglich, Multithreading auf Knoten js mithilfe des Worker_Threads- Moduls zu implementieren. Nach meinen Beobachtungen kann ich auf einem Server mit einem Single-Core-Prozessor auf einem kostenlosen Heroku-Konto drei Threads starten. Drei Streams mit jeweils einem separaten Browser, die gleichzeitig arbeiten können, ohne sich gegenseitig zu blockieren. Fairerweise stelle ich fest, dass sich die Download-Geschwindigkeit einer Kachel aufgrund der erhöhten Belastung des Prozessors sogar geringfügig erhöht hat. Wenn Sie jedoch versuchen, eine Karte für den gesamten Bildschirm herunterzuladen, hat nach 30 Sekunden mehr als die Hälfte der Karte Zeit zum Laden. Mehr als 12 Fliesen. Schon besser.


Drittens. In der aktuellen Implementierung des Skripts verbringen wir bei jeder Anforderung Zeit damit, den Chrome-Browser herunterzuladen und dann abzuschließen. Jetzt werden wir im Voraus einen Browser erstellen und einen Link in mapshoter.js darauf übertragen. Infolgedessen ändert sich die Geschwindigkeit bei der ersten Anforderung nicht. Bei allen nachfolgenden Downloads wird die Geschwindigkeit einer Kachel jedoch auf 4 Sekunden reduziert. Und nach 30 Sekunden hat die gesamte Karte Zeit zum Laden - alle 24 Kacheln, die auf meinem Bildschirm platziert sind.


Wenn Sie dies alles implementieren, kann das Skript durchaus brauchbar werden. Also fangen wir an. Für eine einfachere Arbeit mit Multithreading verwende ich das Node-Worker-Threads-Pool- Modul - eine Art Wrapper über worker_threads. Lassen Sie es uns installieren.


$ npm install node-worker-threads-pool --save


Korrigieren Sie die Datei router.js. Fügen Sie dazu die Erstellung eines Thread-Pools hinzu. Die Fäden werden 3 Stück sein. Ihr Code wird in der Datei worker.js beschrieben , wir werden ihn später betrachten. Löschen Sie in der Zwischenzeit den Start des Screenshot-Moduls direkt. Stattdessen fügen wir dem Thread-Pool eine neue Aufgabe hinzu. Sie beginnen mit der Verarbeitung, wenn einer der Threads freigegeben wird.


 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', async ( req, res, next ) => { const x = req.params.x const y = req.params.y const z = req.params.z //       //       const screenshot = await workersPool.exec( { x, y, z } ) const imageBuffer = Buffer.from( screenshot, 'base64' ) res.writeHead( 200, { 'Content-Type': 'image/png', 'Content-Length': imageBuffer.length }) res.end( imageBuffer ) }) 

Schauen Sie sich jetzt die Datei worker.js an . Jedes Mal, wenn eine neue Aufgabe eintrifft, wird die Methode parentPort.on () gestartet. Leider kann es keine asynchronen / wartenden Funktionen verarbeiten. Daher werden wir die Adapterfunktion in Form der Methode doMyAsyncCode () verwenden.


In einem bequemen lesbaren Format werden wir die Logik des Arbeiters einfügen. Starten Sie also den Browser (falls er noch nicht ausgeführt wird) und aktivieren Sie die Methode zum Erstellen eines Screenshots. Beim Start übergeben wir in diese Methode einen Link zum laufenden Browser.


 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/aswit //     async function doMyAsyncCode( params ) { //      await prepareEnviroment() //     const screenshot = await mapshoter.makeTile( params.x, params.y, params.z, browser ) return screenshot } //  .     ,    async function prepareEnviroment( ) { if ( browser === "empty" ) { const herokuDeploymentParams = {'args' : ['--no-sandbox', '--disable-setuid-sandbox']} browser = await puppeteer.launch( herokuDeploymentParams ) } } 

Kehren wir zur Klarheit zur ersten Version von mapshoter.js zurück . Es wird sich nicht viel ändern. In den Eingabeparametern wird nun ein Link zum Browser akzeptiert, und wenn das Skript endet, wird der Browser nicht ausgeschaltet, sondern einfach die erstellte Registerkarte geschlossen.


 const puppeteer = require( 'puppeteer' ) const geoTools = require( './geoTools' ) async function makeTile( x, y, z, browserLink ) { //      const browser = await browserLink //      const page = await browser.newPage() await page.setViewport( { width: 660, height: 400 } ) const coordinates = geoTools.getAllCoordinates( x, y, z ) const centerCoordinates = `${z}/${coordinates.center.lat}/${coordinates.center.lon}&l=` const pageUrl = 'https://nakarte.me/#m=' + centerCoordinates + "O/Wp" await page.goto( pageUrl, { waitUntil: 'networkidle0', timeout: 20000 } ) const cropOptions = { fullPage: false, clip: { x: 202, y: 67, width: 256, height: 256 } } const screenshot = await page.screenshot( cropOptions ) //   .   . await page.close() return screenshot } module.exports.makeTile = makeTile 

Im Prinzip ist das alles. Jetzt können Sie das Ergebnis auf eine für Sie bequeme Weise auf den Server hochladen. Zum Beispiel über Docker. Wenn Sie sich das fertige Ergebnis ansehen möchten, können Sie auf diesen Link klicken. Den vollständigen Projektcode finden Sie auch auf meinem GitHub .


Fazit


Lassen Sie uns nun das Ergebnis bewerten. Einerseits ist die Download-Geschwindigkeit trotz aller Tricks immer noch sehr niedrig. Darüber hinaus ist eine solche Karte aufgrund der Bremsen einfach unangenehm zu scrollen.


Andererseits bewältigt dieses Skript dennoch Karten, bei denen es zuvor im Allgemeinen unmöglich war, eine Verbindung zum Navigator auf dem Smartphone herzustellen. Es ist unwahrscheinlich, dass diese Lösung jemals als Hauptmethode zum Abrufen kartografischer Daten angewendet wird. Aber hier als zusätzliche, mit deren Hilfe es bei Bedarf möglich sein wird, eine exotische Karte zu öffnen - es ist durchaus möglich.


Zu den Vorteilen dieses Skripts gehört auch die Tatsache, dass es einfach ist, damit zu arbeiten. Es ist leicht zu schreiben. Und vor allem kann es extrem einfach wiederholt werden, eine andere Online-Karte anzuschließen.


Nun, im nächsten Artikel werde ich mich genau damit befassen. Ich werde das Skript in eine Art API für die Arbeit mit der interaktiven OverpassTurbo-Karte umwandeln.

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


All Articles