Mapy Google i JavaFX: wyświetl znacznik na mapie po kliknięciu przycisku JavaFX

359

Próbowałem wyświetlić znacznik na mapie po kliknięciu przycisku mojej aplikacji JavaFX. Tak więc dzieje się, gdy klikam ten przycisk, zapisuję pozycję w pliku JSON, plik ten zostanie załadowany do pliku HTML zawierającego mapę. Problem polega na tym, że działa idealnie, gdy otwieram stronę html w przeglądarce, ale w widoku JavaFX nic się nie dzieje i nie wiem dlaczego!

To jest plik HTML:

<!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>

Po kliknięciu przycisku wypełniam plik JSON (który działa idealnie), a następnie uruchamiam go, aby odświeżyć widok:

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

Jak powiedziałem wcześniej, kiedy otwieram plik w przeglądarce, widzę oczekiwany wynik, ale nie wiem na czym polega problem z JavaFX. Jeśli istnieje lepszy sposób, aby to zrobić, proszę mi powiedzieć.

EDYTOWAĆ:

Znalazłem rozwiązanie problemu, wysyłając bezpośrednio dane (współrzędne GPS) z JavaFX do Javascript przy użyciu metody executeScript (), więc nie potrzebuję pliku json jako pomostu między dwiema platformami. To jest przykład tego, jak wygląda kod:

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

A oto 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);
  }

Dziękujemy za komentarze i odpowiedzi oraz specjalną strzelaninę do redditu.

Chandler Bing
źródło
1
Chociaż skrypt nie jest napisany w najlepszy możliwy sposób, nie ma w nim nic złego. Istnieje kilka możliwości, które mogą sprawić, że nie będzie działać. Upewnij się, że nowy znacznik został dodany na początku pliku json. Przekaż cache: falsedo wywołania ajax, jeśli jest buforowane, i upewnij się, że wybrałeś właściwy plik. Również niektóre logi tu i tam pomogą zidentyfikować problem.
Gökhan Kurt
1
Czy to możliwe, że JavaFX ma problemy z użyciem ajax do odbierania połączeń / danych z punktów końcowych obsługiwanych poza HTTP, takich jak twój test.json?
Sebastian,
@Sebastian Co doprowadza mnie do szału, to że po otwarciu aplikacji plik json jest ładowany poprawnie i widzę oczekiwany wynik. Problem polega na tym, że kiedy aktualizuję plik json inną wartością (gdy aplikacja jest otwarta), po prostu nie chce odświeżyć, aby wyświetlić nowy znacznik! Więc nie ma problemu z wywołaniami ajax. Ale czy może to być oddzwanianie? ponieważ funkcja initMap () jest wywoływana podczas ładowania strony
Chandler Bing
@ GökhanKurt czy przeczytałbyś powyższą odpowiedź
Chandler Bing

Odpowiedzi:

70

Gdybym musiał zgadywać - dzieje się jedna z dwóch rzeczy:

Albo A) twój javaFX nie obsługuje wywołań ajax dla wielu witryn lub B) nie czeka na asynchroniczną odpowiedź ajax / coś innego się nie udaje.

Więc zróbmy razem kilka testów. Po pierwsze, czy możemy to wyczyścić, aby zagnieżdżać wywołania ajax? Następnie możesz dodać niektóre instrukcje console.log, aby dowiedzieć się, co każda z nich odsyła? Jeśli przegapisz jakieś wyjście, wiemy, gdzie idzie źle, i to pomoże nam to naprawić.

Uwaga Zmieniłem sukces na „gotowe” dodatki, ponieważ sukces jest nieco nieaktualny, a wszystko jest zagnieżdżone, aby wyeliminować pytanie, czy jakieś puste są wysyłane do następnych połączeń (problemy z synchronizacją):

$.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);
});

Oto link dotyczący wprowadzania danych wyjściowych console.log do System.out w Javie, jeśli jest to problem: JavaFX 8 WebEngine: Jak uzyskać console.log () z javascript do System.out w Javie?

... również witam z reddit.

David G.
źródło
Cześć, więc myślisz, że problem dotyczy wywołań ajax. Ok, spróbuję znaleźć inny sposób na wysłanie pozycji GPS do javascript (za pomocą executescript).
Chandler Bing
Nie, to nie są wywołania ajax. Problem polega na tym, że nie mogę odświeżyć widoku internetowego, aby pokazać nowy znacznik. Po otwarciu aplikacji wyświetlana jest mapa, co oznacza, że ​​wywołania ajax działają poprawnie.
Chandler Bing
18

W linii:

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

Spróbowałbym dwukrotnie sprawdzić, czy ścieżka do pliku jest poprawna. Czytając inne odpowiedzi na StackOverflow, wygląda na to, że powinno to być względne względem katalogu głównego pakietu i albo z wiodącym '/' lub bez niego. to znaczygetResource("data/index.html") . Ale z drugiej strony, być może zobaczysz już błędy związane z getResource()...

Następnym krokiem do debugowania będzie komentarz do części, w której piszesz JSON, i po prostu ręcznie napisz dobry JSON i po prostu spróbuj go wyświetlić w webView. Im mniej części ruchomych, tym lepiej. Jeśli możesz zmusić go do pracy ze wstępnie napisanym JSON, możesz założyć, że jest jakiś problem z JSON, który piszesz w Javie, a następnie jest ładowany do HTML.

Edycja: Kopałem trochę głębiej. Może to znowu być całkowicie błędne, ale może możesz spróbować ręcznie wywołać initMap()funkcję z Javy, którą przeglądarka zwykle wywołuje podczas ładowania. Jak wywołać funkcję JavaScript z JavaFX WebView po kliknięciu przycisku? ma więcej szczegółów. Spróbuj this.webView.getEngine().executeScript("initMap()");po edycji JSON za pomocą przycisku.

Edycja 2 Nawiasem mówiąc, sensowne może być podzielenie initMapna funkcję initMapi updateMaprozpoczęcie mapy od ustawienia, a następnie ustawienie znaczników na mapie. Chociaż to prawie nic nie psuje.

Matt
źródło
Nie, to nie jest problem, wyświetlam mapę, kiedy otwieram aplikację, z której korzystam. Ale kiedy klikam przycisk, chcę umieścić znacznik na mapie. Ale nie mogę odświeżyć mapy, aby pokazać na niej znacznik.
Chandler Bing
1
Ach, gotcha. Źle zrozumiałem. Czy mówisz, że strona podstawowa ładuje się, ale nie ładują się żadne znaczniki? Czy mapa wyświetla się przynajmniej w twoim webView? Myślę, że możesz być przy czymś, jak wspomniałeś initMap powyżej. Jeśli wywołuje tę funkcję tylko podczas wczytywania strony, prawdopodobnie nie wprowadza zmian w pliku json. Będziesz musiał odświeżyć stronę w widoku sieci lub poprosić stronę, aby ponownie wywołała initMap - może przez ajax? Chyba że JavaFX może uzyskać webView do wywoływania funkcji javascript
Matt
Po otwarciu aplikacji ładowane jest wszystko, co istnieje w pliku json. Ale kiedy zmieniam wartość, gdy aplikacja jest otwarta, chcę odświeżyć widok internetowy, aby zobaczyć zmianę. Ale to po prostu nie działa! To jest problem.
Chandler Bing
1
Zobacz moją edycję - czy dodanie ręcznego wywołania z Javy do funkcji initMap pomaga?
Matt
4

Jeśli kółko myszy służy do pomniejszania lub przybliżania mapy i pojawia się znacznik, oznacza to, że mam ten sam problem, co ja.

Spróbuj ręcznie powiększyć widok mapy, aby przywrócić znaczniki. Musiałem także zastosować tę technikę podczas wyświetlania trasy z usługi kierowania, w przeciwnym razie znaczniki punktów trasy nie byłyby wyświetlane poprawnie.

Oto kod w mojej klasie kontrolera Javafx, aby to zrobić:

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);

Wykorzystano GMapsFX, który jest cienkim opakowaniem Java wokół wywołań silnika javascript w JavaFX WebView. Mam nadzieję, że to pomaga.

Fraser
źródło