Google Maps y JavaFX: muestra el marcador en el mapa después de hacer clic en el botón JavaFX

359

He estado tratando de mostrar un marcador en el mapa cuando hago clic en un botón de mi aplicación JavaFX. Entonces, lo que sucede es que cuando hago clic en ese botón, escribo la posición en un archivo JSON, este archivo se cargará en el archivo html que contiene el mapa. El problema es que funciona perfectamente cuando abro la página html en el navegador, pero no sucede nada en la vista web de JavaFX, ¡y no sé por qué!

Este es el archivo 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>

Cuando hago clic en el botón, lleno el archivo JSON (que funciona perfectamente) y luego lo ejecuto para actualizar la vista web:

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

Como dije antes, cuando abro el archivo en el navegador veo el resultado esperado, pero no sé cuál es el problema con el JavaFX. Si hay una mejor manera de hacerlo, dígamelo.

EDITAR:

Encontré una solución al problema enviando directamente los datos (las coordenadas GPS) de JavaFX a Javascript usando el método executeScript (), por lo que no necesito un archivo json como puente entre las dos plataformas. Así que este es un ejemplo de cómo se ve el código:

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

Y aquí está el 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);
  }

Gracias por sus comentarios y respuestas, y un tiroteo especial para reddit.

Chandler Bing
fuente
48
Para referencia: reddit.com/r/ProgrammerHumor/comments/6e6wu6/…
Mateen Ulhaq
1
Aunque el guión no está escrito de la mejor manera posible, no parece tener nada de malo. Hay un par de posibilidades que pueden hacer que no funcione. Asegúrese de que el nuevo marcador se agrega a la parte superior del archivo json. Pase cache: falsea la llamada ajax en caso de que esté en caché y asegúrese de apuntar al archivo correcto. También algunos registros aquí y allá ayudarían a identificar el problema.
Gökhan Kurt
1
¿Podría ser que JavaFX tiene problemas al usar ajax para recibir llamadas / datos de puntos finales no atendidos por HTTP como su test.json?
Sebastian
@Sebastian Lo que me está volviendo loco es que cuando abro la aplicación, el archivo json se carga correctamente y veo el resultado esperado. El problema es que cuando actualizo el archivo json con otro valor (mientras la aplicación está abierta) ¡simplemente no quiere actualizar para mostrar el nuevo marcador! Por lo tanto, no hay problema con las llamadas ajax. Pero, ¿puede ser la devolución de llamada? porque se llama a initMap () mientras se carga la página
Chandler Bing
@ GökhanKurt, ¿podría leer la respuesta anterior
Chandler Bing

Respuestas:

70

Si tuviera que adivinar, una de dos cosas está sucediendo:

A) su javaFX no admite llamadas ajax entre sitios o B) no está esperando la respuesta asíncrona ajax / algo más está saliendo mal.

Así que hagamos algunas pruebas juntos. En primer lugar, ¿podemos limpiar esto para anidar las llamadas ajax? Entonces, ¿puede agregar algunas declaraciones de console.log para averiguar qué está enviando cada una? Si pierde algún resultado, sabemos dónde va mal y eso nos ayudará a arreglar las cosas.

Tenga en cuenta que he cambiado el éxito a las adiciones 'hechas' porque el éxito está un poco desactualizado y todo está anidado para eliminar la pregunta sobre si se están enviando espacios en blanco a las próximas llamadas (problemas de sincronización):

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

Aquí hay un enlace para obtener la salida de console.log en System.out en Java si esto es un problema: JavaFX 8 WebEngine: ¿Cómo obtener console.log () de javascript a System.out en java?

... También hola de reddit.

David G
fuente
Hola, entonces piensas que el problema es con las llamadas ajax. Ok, intentaré encontrar otra forma de enviar las posiciones de GPS a javascript (usando executetescript).
Chandler Bing
No, no son las llamadas ajax. El problema es que no puedo actualizar la vista web para mostrar el nuevo marcador. Cuando abro la aplicación, se muestra el mapa, lo que significa que las llamadas ajax funcionan bien.
Chandler Bing
18

En la linea:

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

Intentaría verificar que la ruta al archivo sea correcta. Al leer otras respuestas en StackOverflow, parece que se supone que esto es relativo a la raíz del paquete y con o sin el '/' inicial. es decir getResource("data/index.html"). Pero, de nuevo, tal vez ya estarías viendo errores relacionados con getResource()...

Mi próximo paso, para fines de depuración, sería comentar la parte en la que escribes el JSON y solo escribes manualmente un buen JSON e intenta que aparezca en la vista web. Cuantas menos partes móviles, mejor. Si puede hacer que funcione con su JSON preescrito, entonces puede suponer que es un problema con el JSON que está escribiendo con Java y luego se carga en el HTML.

Editar: cavé un poco más profundo. Esto podría estar totalmente equivocado nuevamente, pero tal vez pueda intentar llamar manualmente a la initMap()función desde Java que su navegador web normalmente llama onload. ¿Cómo llamar a una función de JavaScript desde un JavaFX WebView al hacer clic en el botón? Tiene algunos detalles más. Intente this.webView.getEngine().executeScript("initMap()");después de editar el JSON con su botón.

Editar 2 Como acotación al margen, también, podría tener sentido para dividir initMapen una initMapy la updateMapfunción para hacer el mapa, para empezar, y luego poner los marcadores en el mapa. Aunque esto apenas está rompiendo nada.

Mate
fuente
No, ese no es el problema, muestro el mapa cuando abro la aplicación y firmo esa línea. Pero cuando hago clic en un botón, quiero poner un marcador en el mapa. Pero no puedo actualizar el mapa para mostrar el marcador en él.
Chandler Bing
1
Ah, te tengo. Entendí mal. ¿Estás diciendo que la página básica se está cargando pero no se están cargando marcadores? ¿Aparece el mapa en su vista web al menos? Creo que puede estar haciendo algo como mencionó initMap anteriormente. Si solo está llamando a esa función en la carga de la página, entonces probablemente no esté recibiendo ediciones en el json. Tendría que actualizar la página dentro de la vista web o decirle a la página que vuelva a llamar a initMap de alguna manera, ¿tal vez a través de ajax? A menos que JavaFX pueda hacer que webView llame a las funciones de JavaScript
Matt
Cuando se abre la aplicación, se carga todo lo que existe en el archivo json. Pero cuando cambio un valor mientras la aplicación está abierta, quiero actualizar la vista web para ver el cambio. ¡Pero simplemente no funciona! Este es el problema.
Chandler Bing
1
Vea mi edición: ¿ayuda agregar una llamada manual desde Java a la función initMap?
Matt
4

Si usa la rueda del mouse para acercar o alejar el mapa y aparece el marcador, entonces está experimentando el mismo problema que yo.

Intente acercar manualmente la vista del mapa para restaurar los marcadores. También tuve que emplear esta técnica al mostrar una ruta desde el Servicio de indicaciones, de lo contrario los marcadores de puntos de ruta no se mostraban correctamente.

Este es el código en mi clase de controlador Javafx para hacerlo:

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

Esto estaba usando GMapsFX, que es solo una delgada envoltura de Java alrededor de las llamadas del motor de JavaScript en un JavaFX WebView. Espero que ayude.

Fraser
fuente