Google Maps & JavaFX: Zeigen Sie die Markierung auf der Karte an, nachdem Sie auf die Schaltfläche JavaFX geklickt haben

359

Ich habe versucht, eine Markierung auf der Karte anzuzeigen, wenn ich auf eine Schaltfläche meiner JavaFX-Anwendung klicke. Wenn ich also auf diese Schaltfläche klicke, schreibe ich die Position in eine JSON-Datei. Diese Datei wird in die HTML-Datei geladen, die die Karte enthält. Das Problem ist, dass es perfekt funktioniert, wenn ich die HTML-Seite im Browser öffne, aber in der Webansicht von JavaFX nichts passiert und ich nicht weiß warum!

Dies ist die HTML-Datei:

<!DOCTYPE html>
<html>
  <head>
  <title>Simple Map</title>
  <meta name="viewport" content="initial-scale=1.0">
  <meta charset="utf-8">
  <style>
  /* Always set the map height explicitly to define the size of the div
   * element that contains the map. */
  /*#map {
    height: 100%;
  }*/
  #map{width:100%;height:100%;margin:auto;}
  /* Optional: Makes the sample page fill the window. */
  html, body {
    height: 100%;
    margin: 0;
    padding: 0;
  }
</style>
</head>
<body>
<div id="map"></div>
<script>
  var map;
  var marker;
  // Multiple Markers
  var markers = [];
  var pos = {lat: 46.662388, lng: 0.3599617};
  var itinerary_markers = [];

  function initMap() {

    var currentLat, currentLng;//Latitude et longtitude courante

    $.ajax({
      url: 'https://maps.googleapis.com/maps/api/geocode/json?address=My+ADDRESS&key=MY_KEY',
      async: false,
      dataType: 'json',
      success: function (data) {
        currentLat = data.results[0].geometry.location.lat;
        currentLng = data.results[0].geometry.location.lng;
      }
    });

    map = new google.maps.Map(document.getElementById('map'), {
      center: {lat: currentLat, lng: currentLng},
      zoom: 15,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    });


    /*MARQUEUR*/ 
    $.ajax({
        async: false,
        url: 'test.json',
        data: "",
        accepts:'application/json',
        dataType: 'json',
        success: function (data) {
            for (var i = 0; i < data.hydrants.length; i++) {
                markers.push( data.hydrants[i]);
            }
        }
    });

      var posi = new google.maps.LatLng(markers[0].Lat, markers[0].Lng);
      marker = new google.maps.Marker({
          position: posi,
          map: map,
          //title: markers[i][0]
          title: markers[0].Name
        });

  }
</script>

<script
    src="https://code.jquery.com/jquery-3.2.1.min.js"
    integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
    crossorigin="anonymous">
</script>


<script src="https://maps.googleapis.com/maps/api/js?key=MY_KEY&callback=initMap&language=fr"
async defer></script>

</body>
</html>

Wenn ich auf die Schaltfläche klicke, fülle ich die JSON-Datei (die perfekt funktioniert) und führe diese aus, um die Webansicht zu aktualisieren:

this.webView.getEngine().load(getClass().getResource("/data/index.html").toString());

Wie ich bereits sagte, sehe ich beim Öffnen der Datei im Browser das erwartete Ergebnis, weiß aber nicht, wo das Problem mit JavaFX liegt. Wenn es einen besseren Weg gibt, sag es mir bitte.

BEARBEITEN:

Ich habe eine Lösung für das Problem gefunden, indem ich die Daten (die GPS-Koordinaten) mit der Methode executeScript () direkt von JavaFX an Javascript gesendet habe. Daher benötige ich keine JSON-Datei als Brücke zwischen den beiden Plattformen. Dies ist also ein Beispiel dafür, wie der Code aussieht:

eng.executeScript("updateMarker(" + lat + ", " + lng + ")");//eng is a WebEngine instance

Und hier ist das Javascript:

/*The initial latitude and longtitude*/
var currentLat = the latitude;
var currentLng = the longtitude;

function initMap() {

    map = new google.maps.Map(document.getElementById('map'), {
      center: {lat: currentLat, lng: currentLng},
      zoom: 15,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    });

    var posi = new google.maps.LatLng(currentLat, currentLng);
    marker = new google.maps.Marker({
        position: posi,
        map: map,
        visible: false
    });
  }

/*The method that is I call from JavaFX*/
function updateMarker(_lat, _lng){
    marker.setPosition({lat: _lat, lng: _lng});
    map.setCenter(new google.maps.LatLng(_lat, _lng));
    marker.setVisible(true);
  }

Vielen Dank für Ihre Kommentare und Antworten sowie für ein spezielles Shootout zum Reddit.

Chandler Bing
quelle
48
Als Referenz: reddit.com/r/ProgrammerHumor/comments/6e6wu6/…
Mateen Ulhaq
1
Obwohl das Skript nicht optimal geschrieben ist, scheint daran nichts auszusetzen. Es gibt einige Möglichkeiten, die dazu führen können, dass es nicht funktioniert. Stellen Sie sicher, dass der neue Marker oben in der JSON-Datei hinzugefügt wird. Übergeben Sie cache: falseden Ajax-Aufruf, falls er zwischengespeichert ist, und stellen Sie sicher, dass Sie auf die richtige Datei abzielen. Auch einige Protokolle hier und da würden helfen, das Problem zu identifizieren.
Gökhan Kurt
1
Könnte es sein, dass das JavaFX-Ding Probleme hat, Ajax zum Empfangen von Anrufen / Daten von Nicht-HTTP-Endpunkten wie Ihrer test.json zu verwenden?
Sebastian
@Sebastian Was mich verrückt macht, ist, dass beim Öffnen der App die JSON-Datei korrekt geladen wird und ich das erwartete Ergebnis sehe. Das Problem ist, wenn ich die JSON-Datei mit einem anderen Wert aktualisiere (während die App geöffnet ist), möchte sie einfach nicht aktualisiert werden, um den neuen Marker anzuzeigen! Es gibt also kein Problem mit den Ajax-Aufrufen. Aber kann es der Rückruf sein? weil die initMap () aufgerufen wird, während die Seite geladen wird
Chandler Bing
@ GökhanKurt würden Sie die Antwort oben lesen
Chandler Bing

Antworten:

70

Wenn ich raten müsste - eines von zwei Dingen passiert:

Entweder A) Ihr JavaFX unterstützt keine standortübergreifenden Ajax-Aufrufe oder B) es wartet nicht auf die asynchrone Ajax-Antwort / etwas anderes läuft schief.

Lassen Sie uns also gemeinsam einige Tests durchführen. Erstens können wir dies bereinigen, um die Ajax-Aufrufe zu verschachteln? Können Sie dann einige console.log-Anweisungen hinzufügen, um herauszufinden, was die einzelnen zurücksenden? Wenn Sie eine Ausgabe verpassen, wissen wir, wo sie falsch läuft, und das hilft uns, die Probleme zu beheben.

Hinweis: Ich habe den Erfolg in die "erledigten" Ergänzungen geändert, da der Erfolg etwas veraltet ist und alles verschachtelt ist, um die Frage zu beseitigen, ob bei den nächsten Aufrufen Leerzeichen gesendet werden (Synchronizitätsprobleme):

$.ajax({
    url: 'https://maps.googleapis.com/maps/api/geocode/json?address=My+ADDRESS&key=MY_KEY',
    async: false,
    dataType: 'json'
}).done(function(data) {
    currentLat = data.results[0].geometry.location.lat;
    currentLng = data.results[0].geometry.location.lng;
    console.log(currentLat);
    console.log(currentLng);
    // Multiple Markers
    var markers = [];
    var pos = {lat: 46.662388, lng: 0.3599617};
    var itinerary_markers = [];
    var map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: currentLat, lng: currentLng},
        zoom: 15,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    });
    console.log(map);
    /*MARQUEUR*/ 
    $.ajax({
        async: false,
        url: 'test.json',
        data: "",
        accepts:'application/json',
        dataType: 'json'
    }).done(function(data) {
        for (var i = 0; i < data.hydrants.length; i++) {
            markers.push( data.hydrants[i]);
        }
        console.log(markers);
        var posi = new google.maps.LatLng(markers[0].Lat, markers[0].Lng);
        console.log(posi);
        var marker = new google.maps.Marker({
            position: posi,
            map: map,
            //title: markers[i][0]
            title: markers[0].Name
        });
        console.log(marker);
    }).fail(function(jqXHR, testStatus){
        console.log(textStatus);
    });
}).fail(function(jqXHR, testStatus){
    console.log(textStatus);
});

Hier ist ein Link zum Abrufen der Ausgabe von console.log in System.out in Java, wenn dies ein Problem darstellt: JavaFX 8 WebEngine: Wie wird console.log () von JavaScript zu System.out in Java abgerufen?

... auch hallo von reddit.

David G.
quelle
Hallo, Sie denken also, dass das Problem bei Ajax-Anrufen liegt. Ok, ich werde versuchen, einen anderen Weg zu finden, um die GPS-Positionen an Javascript zu senden (mit Executescript).
Chandler Bing
Nein, es sind nicht die Ajax-Anrufe. Das Problem ist, dass ich die Webansicht nicht aktualisieren kann, um den neuen Marker anzuzeigen. Wenn ich die App öffne, wird die Karte angezeigt, was bedeutet, dass die Ajax-Aufrufe einwandfrei funktionieren.
Chandler Bing
18

In der Schlange:

this.webView.getEngine().load(getClass().getResource("/data/index.html").toString());

Ich würde versuchen, den Pfad zur Datei noch einmal zu überprüfen. Wenn Sie andere Antworten auf StackOverflow lesen, sieht es so aus, als ob dies relativ zum Paketstamm und entweder mit oder ohne das führende '/' sein sollte. dh getResource("data/index.html"). Aber andererseits würden Sie vielleicht bereits Fehler im Zusammenhang mit getResource()...

Zum Debuggen würde ich als Nächstes den Teil auskommentieren, in dem Sie den JSON schreiben, und einfach manuell einen guten JSON schreiben und versuchen, ihn in der Webansicht anzuzeigen. Je weniger bewegliche Teile, desto besser. Wenn Sie es mit Ihrem vorab geschriebenen JSON zum Laufen bringen können, können Sie davon ausgehen, dass es ein Problem mit dem JSON gibt, das Sie mit Java schreiben, und es dann in den HTML-Code geladen wird.

Edit: Ich habe etwas tiefer gegraben. Dies könnte wieder völlig falsch sein, aber vielleicht können Sie versuchen, die initMap()Funktion von Java, die Ihr Webbrowser normalerweise beim Laden aufruft, manuell aufzurufen. Wie rufe ich eine JavaScript-Funktion aus einem JavaFX-WebView auf, wenn ich auf die Schaltfläche klicke? hat einige weitere Details. Versuchen this.webView.getEngine().executeScript("initMap()");Sie es, nachdem Sie den JSON mit Ihrer Schaltfläche bearbeitet haben.

Bearbeiten 2 Nebenbei kann es auch sinnvoll sein, sich initMapin eine initMapund eine updateMapFunktion aufzuteilen , um die Karte zu erstellen und dann die Markierungen auf der Karte zu setzen. Obwohl dies kaum etwas bricht.

Matt
quelle
Nein, das ist nicht das Problem. Ich zeige die Karte an, wenn ich die App öffne und diese Zeile benutze. Wenn ich jedoch auf eine Schaltfläche klicke, möchte ich eine Markierung auf der Karte platzieren. Ich kann die Karte jedoch nicht aktualisieren, um die Markierung darauf anzuzeigen.
Chandler Bing
1
Ah, gotcha. Ich habe es falsch verstanden. Wollen Sie damit sagen, dass die Basisseite geladen wird, aber keine Markierungen geladen werden? Wird die Karte mindestens in Ihrer Webansicht angezeigt? Ich denke, Sie haben vielleicht etwas vor, wie Sie oben in initMap erwähnt haben. Wenn diese Funktion nur beim Laden der Seite aufgerufen wird, werden wahrscheinlich keine Änderungen am JSON vorgenommen. Sie müssten die Seite in der Webansicht aktualisieren oder die Seite anweisen, initMap erneut aufzurufen - möglicherweise über Ajax? Es sei denn, JavaFX kann das WebView dazu bringen, Javascript-Funktionen aufzurufen
Matt
Beim Öffnen der App wird alles geladen, was in der JSON-Datei vorhanden ist. Wenn ich jedoch einen Wert ändere, während die App geöffnet ist, möchte ich die Webansicht aktualisieren, um die Änderung zu sehen. Aber es funktioniert einfach nicht! Das ist das Problem.
Chandler Bing
1
Siehe meine Bearbeitung - Hilft das Hinzufügen eines manuellen Aufrufs von Java zur initMap-Funktion?
Matt
4

Wenn Sie mit dem Mausrad die Karte vergrößern oder verkleinern und die Markierung angezeigt wird, tritt das gleiche Problem auf wie bei mir.

Versuchen Sie, die Kartenansicht manuell zu zoomen, um die Markierungen wiederherzustellen. Ich musste diese Technik auch anwenden, wenn ich eine Route vom Wegbeschreibungsdienst anzeigte, da sonst die Wegpunktmarkierungen nicht korrekt angezeigt wurden.

Dies ist der Code in meiner Javafx-Controller-Klasse, um dies zu tun:

KeyFrame kf1 = new KeyFrame(Duration.seconds(0.75), e -> map.setZoom(map.getZoom() - 1));
KeyFrame kf2 = new KeyFrame(Duration.seconds(1.5), e -> map.setZoom(map.getZoom() + 1));
Timeline timeline = new Timeline(kf1, kf2);
Platform.runLater(timeline::play);

Hierbei wurde GMapsFX verwendet, ein dünner Java-Wrapper für Javascript-Engine-Aufrufe in einem JavaFX-WebView. Hoffentlich hilft es.

Fraser
quelle