Google Maps e JavaFX: exiba o marcador no mapa depois de clicar no botão JavaFX

359

Eu tenho tentado exibir um marcador no mapa quando clico em um botão do meu aplicativo JavaFX. Então, o que acontece é que, quando clico nesse botão, escrevo a posição em um arquivo JSON, esse arquivo será carregado no arquivo html que contém o mapa. O problema é que ele funciona perfeitamente quando abro a página html no navegador, mas nada acontece na exibição da Web do JavaFX e não sei por que!

Este é o arquivo 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>

Quando clico no botão, preencho o arquivo JSON (que funciona perfeitamente) e, em seguida, executo-o para atualizar a visualização da web:

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

Como eu disse antes, quando abro o arquivo no navegador, vejo o resultado esperado, mas não sei qual é o problema com o JavaFX. Se houver uma maneira melhor de fazer isso, por favor me diga.

EDITAR:

Encontrei uma solução para o problema enviando diretamente os dados (as coordenadas GPS) de JavaFX para Javascript usando o método executeScript (), para que não precise de um arquivo json como ponte entre as duas plataformas. Portanto, este é um exemplo de como o código se parece:

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

E aqui está o 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);
  }

Obrigado por seus comentários e respostas, e um tiroteio especial para reddit.

Chandler Bing
fonte
48
Para referência: reddit.com/r/ProgrammerHumor/comments/6e6wu6/…
Mateen Ulhaq
11
Embora o script não esteja escrito da melhor maneira possível, não parece haver nada errado com ele. Existem algumas possibilidades que podem fazer com que não funcione. Verifique se o novo marcador foi adicionado à parte superior do arquivo json. Passe cache: falsepara a chamada ajax, caso esteja em cache, e tenha como alvo o arquivo certo. Além disso, alguns logs aqui e ali ajudariam a identificar o problema.
Gökhan Kurt
11
Poderia ser que a coisa JavaFX tenha problemas ao usar o ajax para receber chamadas / dados de pontos de extremidade atendidos não HTTP como o seu test.json?
Sebastian
@Sebastian O que está me deixando louco é que, quando abro o aplicativo, o arquivo json é carregado corretamente e vejo o resultado esperado. O problema é que, quando atualizo o arquivo json com outro valor (enquanto o aplicativo está aberto), ele simplesmente não deseja atualizar para exibir o novo marcador! Portanto, não há problema com as chamadas ajax. Mas pode ser a coisa de retorno de chamada? porque o initMap () é chamado enquanto a página está sendo carregada
Chandler Bing
@ GökhanKurt você leria a resposta acima #
Chandler Bing

Respostas:

70

Se eu tivesse que adivinhar - uma das duas coisas está acontecendo:

A) seu javaFX não suporta chamadas ajax entre sites ou B) não aguarda a resposta assíncrona do ajax / algo está errado.

Então, vamos fazer alguns testes juntos. Em primeiro lugar, podemos limpar isso para aninhar as chamadas ajax? Em seguida, você pode adicionar algumas instruções console.log para descobrir o que cada uma está enviando de volta? Se você perder alguma saída, sabemos onde está dando errado e isso nos ajudará a consertar as coisas.

Observe que mudei o sucesso para as adições 'concluídas' porque o sucesso está um pouco desatualizado e tudo está aninhado para eliminar a questão de saber se algum espaço em branco está sendo enviado para as próximas chamadas (problemas de sincronicidade):

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

Aqui está um link para obter a saída console.log para System.out em Java, se este for um problema: JavaFX 8 WebEngine: Como obter console.log () de javascript para System.out em java?

... Olá também do reddit.

David G
fonte
Olá, você acha que o problema está nas chamadas ajax. Ok, vou tentar encontrar outra maneira de enviar as posições de GPS para javascript (usando executescript).
Chandler Bing
Não, não é o ajax. O problema é que não consigo atualizar a visualização da web para mostrar o novo marcador. Quando abro o aplicativo, o mapa é exibido, o que significa que as chamadas ajax funcionam bem.
Chandler Bing
18

Na linha:

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

Eu tentaria verificar duas vezes o caminho para o arquivo está correto. Lendo outras respostas no StackOverflow, parece que isso deve ser relativo à raiz do pacote e com ou sem o '/' inicial. ie getResource("data/index.html"). Mas, novamente, talvez você já esteja vendo erros relacionados a getResource()...

Meu próximo passo, para fins de depuração, seria comentar a parte em que você escreve o JSON e apenas escrever manualmente um bom JSON e apenas tentar fazê-lo aparecer no webView. Quanto menos partes móveis, melhor. Se você conseguir que ele funcione com seu JSON pré-escrito, poderá assumir que há algum problema com o JSON que você está escrevendo com Java e, em seguida, sendo carregado no HTML.

Edit: Eu cavei um pouco mais fundo. Isso pode estar totalmente errado novamente, mas talvez você possa tentar chamar manualmente a initMap()função de Java que seu navegador normalmente chama de onload. Como chamar uma função JavaScript de um JavaFX WebView no botão Clique? tem mais alguns detalhes. Tente this.webView.getEngine().executeScript("initMap()");depois de editar o JSON com seu botão.

Editar 2 Como um aparte, também, pode fazer sentido dividir-se initMapem uma função initMape updateMappara fazer o mapa começar e depois definir os marcadores no mapa. Embora isso dificilmente esteja quebrando alguma coisa.

Matt
fonte
Não, não é esse o problema, eu mostro o mapa quando abro o aplicativo usando essa linha. Mas quando clico em um botão, quero colocar um marcador no mapa. Mas não consigo atualizar o mapa para mostrar o marcador nele.
Chandler Bing
11
Ah, entendi. Eu entendi errado. Você está dizendo que a página básica está carregando, mas nenhum marcador está sendo carregado? O mapa está aparecendo no seu webView pelo menos? Eu acho que você pode estar interessado em algo como mencionou o initMap acima. Se estiver apenas chamando essa função no carregamento da página, provavelmente não está recebendo edições no json. Você precisaria atualizar a página dentro da visualização na web ou dizer à página para chamar o initMap de alguma forma - talvez através do ajax? A menos que JavaFX pode obter o webView para funções javascript chamada
Matt
Quando o aplicativo é aberto, tudo o que existe no arquivo json é carregado. Mas quando altero um valor enquanto o aplicativo está aberto, desejo atualizar a visualização da web para ver a alteração. Mas isso simplesmente não funciona! Este é o problema.
Chandler Bing
11
Veja minha edição - a adição de uma chamada manual do Java à função initMap ajuda?
Matt
4

Se a roda do mouse for usada para ampliar ou reduzir o mapa e o marcador aparecer, você está enfrentando o mesmo problema que eu.

Tente ampliar manualmente a visualização do mapa para restaurar os marcadores. Eu também tive que empregar essa técnica ao exibir uma rota no serviço de rotas, caso contrário, os marcadores do waypoint não estavam sendo exibidos corretamente.

Este é o código na minha classe de controlador Javafx para fazer isso:

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

Isso estava usando o GMapsFX, que é apenas um fino invólucro Java em torno das chamadas do mecanismo javascript em um JavaFX WebView. Espero que ajude.

Fraser
fonte