Подтвердить что ты не робот

Отключить затухание плитки Google Maps или определить, полностью ли отображена карта?

Вопрос

Есть ли способ отключить затухание плиток карт Google? Или есть способ определить, полностью ли отображена карта?

Проблема

Я хочу получить событие, когда карта будет полностью загружена (и отображена) и сделайте снимок экрана. Я пробовал эти события, как предложено в нескольких ответах

google.maps.event.addListenerOnce(map, 'tilesloaded', function(){
  // screenshot
});

google.maps.event.addListener(map, 'idle', function(){
  // screenshot
});

window.onload = function(e){
  // screenshot
};

но плитки все еще исчезают, даже после того, как все загружено, и вышеупомянутые события запускаются.

Он выглядит так: left - это карты google, справа - автоматический снимок экрана, который берется после запуска событий:

введите описание изображения здесь

код

Код находится в html и JavaFX

demo.html

<!DOCTYPE html>
<html>
<head>

    <script src="http://maps.google.com/maps/api/js?sensor=false"></script>

    <style>
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    #mapcanvas {
      /* height: 4000px; we need the value from java */
      width: 100%
    }
    </style>


</head>
<body>
<div id="mapcanvas"></div>

<script type="text/javascript">

        console.log("Loading map tiles");

        // set map canvas height
        document.getElementById('mapcanvas').style.height = window.mapCanvasHeight;

        document.map = new google.maps.Map(document.getElementById("mapcanvas"));

        // the global window object is used to set variables via java
        var latlng = new google.maps.LatLng(window.lat, window.lon);

        // https://developers.google.com/maps/documentation/javascript/reference?hl=en
        var Options = {
            zoom: 17,
            center: latlng,
            mapTypeId: google.maps.MapTypeId.SATELLITE,
            disableDefaultUI: true,
        };

        var map = new google.maps.Map(document.getElementById("mapcanvas"), Options);
        document.goToLocation = function(x, y) {

            console.log("goToLocation, lat: " + x +", lon:" + y);

            var latLng = new google.maps.LatLng(x, y);
            map.setCenter(latLng);

        }

        // this doesn't work properly because some tiles fade in and hence you get a snapshot with faded tiles
        google.maps.event.addListenerOnce(map, 'tilesloaded', function(){

            console.log("tilesloaded");

            java.onMapLoadingFinished();

        });

        // This event is fired when the map becomes idle after panning or zooming.
        // it works after all tiles were first loaded and you zoom afterwards ( but doesn't work a 100% all the time )
        // initially you still get faded tiles
        google.maps.event.addListener(map, 'idle', function(){

            console.log("idle");

            // java.onMapLoadingFinished();

        });

        window.onload = function(e){

            console.log("window.onload");

            // java.onMapLoadingFinished();

        };

</script>
</body>
</html>

GoogleApp.java

import java.net.URL;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.concurrent.Worker.State;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;

/**
 * Load google maps map and take a snapshot from it
 */
public class GoogleApp extends Application {

    // initial lat/lon
    double lat = 38.897676;
    double lon = -77.036483;

    double browserWidth = 1024; // this is set to 100% in the html css for the map canvas
    double browserHeight = 8000; // this is used in the html map canvas; IMPORTANT: when the app freezes during zoom in, then the problem is probably the height; it works without problems with height of e. g. 360

    MyBrowser webBrowser;
    TextField latitudeTextField;
    TextField longitudeTextField;

    private ScrollPane snapshotScrollPane;

    @Override
    public void start(Stage stage) throws Exception {

        webBrowser = new MyBrowser(browserWidth, browserHeight);

        ScrollPane browserScrollPane = new ScrollPane(webBrowser);
        snapshotScrollPane = new ScrollPane();

        SplitPane splitPane = new SplitPane(browserScrollPane, snapshotScrollPane);

        BorderPane borderPane = new BorderPane();
        borderPane.setCenter(splitPane);
        borderPane.setRight(snapshotScrollPane);

        Scene scene = new Scene(borderPane, 1024, 768);
        stage.setScene(scene);
        stage.show();

    }

    private void createSnapshot() {

        SnapshotParameters parameters = new SnapshotParameters();
        parameters.setFill(Color.TRANSPARENT);

        // new image from clipped image
        WritableImage wim = null;
        wim = webBrowser.snapshot(parameters, wim);

        snapshotScrollPane.setContent(new ImageView(wim));
    }

    public class JavaBridge {

        public void onMapLoadingFinished() {

            System.out.println("[javascript] onMapLoadingFinished");

            createSnapshot();

        }

        public void log(String text) {
            System.out.println("[javascript] " + text);
        }

    }

    private class MyBrowser extends Pane {

        WebView webView;
        WebEngine webEngine;

        public MyBrowser(double width, double height) {

            webView = new WebView();
            webView.setPrefWidth(width);
            webView.setPrefHeight(height);

            webEngine = webView.getEngine();

            webEngine.getLoadWorker().stateProperty().addListener((ChangeListener<State>) (observable, oldState, newState) -> {

                System.out.println("[State] " + observable);

                if (newState == State.SCHEDULED) {

                    System.out.println("Webpage loaded");

                    // inject "java" object
                    JSObject window = (JSObject) webEngine.executeScript("window");
                    JavaBridge bridge = new JavaBridge();
                    window.setMember("java", bridge);

                    // console.log
                    webEngine.executeScript("console.log = function(message)\n" + "{\n" + "    java.log(message);\n" + "};");

                    // initialize variables

                    // canvas height
                    webEngine.executeScript("window.mapCanvasHeight = '" + browserHeight + "px'");

                    System.out.println("Latitude = " + lat + ", Longitude = " + lon);

                    webEngine.executeScript("window.lat = " + lat + ";" + "window.lon = " + lon + ";");

                }

                if (newState == State.SUCCEEDED) {
                    // createSnapshot();
                }
            });

            // logging other properties
            webEngine.getLoadWorker().exceptionProperty().addListener((ChangeListener<Throwable>) (ov, t, t1) -> System.out.println("[Exception] " + t1.getMessage()));
            webEngine.getLoadWorker().progressProperty().addListener((ChangeListener<Number>) (observable, oldState, newState) -> System.out.println( "[Progress] " + newState));
            webEngine.getLoadWorker().workDoneProperty().addListener((ChangeListener<Number>) (observable, oldState, newState) -> System.out.println( "[WorkDone] " + newState));
            webEngine.getLoadWorker().runningProperty().addListener((ChangeListener<Boolean>) (observable, oldState, newState) -> System.out.println( "[Running] " + newState));
            webEngine.getLoadWorker().messageProperty().addListener((ChangeListener<String>) (observable, oldState, newState) -> System.out.println( "[Message] " + newState));


            final URL urlGoogleMaps = getClass().getResource("demo.html");
            webEngine.load(urlGoogleMaps.toExternalForm());

            // TODO: how should that work? it doesn't do anything when we invoke an alert
            webEngine.setOnAlert(e -> System.out.println("Alert: " + e.toString()));

            getChildren().add(webView);

        }

    }

    public static void main(String[] args) {
        launch(args);
    }
}

консольный вывод

[WorkDone] 0.0
[Progress] 0.0
[State] ReadOnlyObjectProperty [bean: [email protected], name: state, value: SCHEDULED]
Webpage loaded
Latitude = 38.897676, Longitude = -77.036483
[Running] true
[State] ReadOnlyObjectProperty [bean: [email protected], name: state, value: RUNNING]
[WorkDone] 50.0
[Progress] 0.5
[WorkDone] 66.66666666666667
[Progress] 0.6666666666666667
[WorkDone] 76.59016927083334
[Progress] 0.7659016927083334
[javascript] Loading map tiles
[WorkDone] 79.69424280262338
[Progress] 0.7969424280262337
[WorkDone] 82.91479192680356
[Progress] 0.8291479192680357
[WorkDone] 86.13534105098375
[Progress] 0.8613534105098376
[WorkDone] 87.9566062307981
[Progress] 0.879566062307981
[WorkDone] 89.554165026828
[Progress] 0.89554165026828
[WorkDone] 89.62836770069038
[Progress] 0.8962836770069037
[javascript] idle
[WorkDone] 89.70492380394815
[Progress] 0.8970492380394814
[WorkDone] 89.78964107398804
[Progress] 0.8978964107398804
[WorkDone] 89.85311355504936
[Progress] 0.8985311355504936
[WorkDone] 89.91528395017954
[Progress] 0.8991528395017955
[WorkDone] 89.9528416875862
[Progress] 0.899528416875862
[javascript] window.onload
[Message] Loading complete
[WorkDone] 100.0
[Progress] 1.0
[State] ReadOnlyObjectProperty [bean: [email protected], name: state, value: SUCCEEDED]
[Running] false
[javascript] tilesloaded
[javascript] onMapLoadingFinished
taking screenshot

Конечно, можно было бы подождать секунду и сделать снимок экрана, но это не правильное решение.

4b9b3361

Ответ 1

События Google Maps привязаны очень индивидуально. Слушатель tilesloaded особенно срабатывает, даже когда карта может быть панорамированием. Это можно увидеть, пытаясь подчеркнуть карту в этом примере слушателей здесь

Кроме того, прослушиватель idle запускается несколько раз во время панорамирования. Лучше всего поместить таймер с установленным временем, чтобы определить, что пользователь полностью остановил панорамирование/масштабирование, а затем сделайте снимок экрана. Вот базовый пример:

google.maps.event.addListener(map, "idle", function () {
    var mapMoveTimer, tileLoadedListener;
    var moveDetect = google.maps.event.addListener(map, "bounds_changed", function () {
        clearTimeout(mapMoveTimer);
    });

    mapMoveTimer = setTimeout(function () {
        google.maps.event.removeListener(moveDetect);

        // here is your code
        tileLoadedListener = google.maps.event.addListenerOnce(map, 'tilesloaded', function(){
            console.log("tilesloaded");
            java.onMapLoadingFinished();

            // make sure to remove the listener so it isn't fired multiple times.
            google.maps.event.removeListener(tileLoadedListener);
        });
    });

    }, 1000);
});

Ответ 2

Мне не удалось найти способ определить, когда карта полностью загружена, но вы можете получить карту в качестве изображения в первую очередь, используя google maps static api https://developers.google.com/maps/documentation/static-maps/intro.

Вот фрагмент кода, который загружает статическую карту:

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
</head>
<body>

<div id="staticView" style="width:400px; height:400px"></div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>

<script type="text/javascript">
  $(document).ready(function() {
    var mapImage = new Image();
    var eltStaticView = $("#staticView");
    $(mapImage).one('load', function() {
      eltStaticView.css('background-image', 'url(' + mapImage.src + ')');
      console.log("Image Has Loaded");
      $(mapImage).unbind();
    });
    $(mapImage).error(function() {
      $(mapImage).unbind();
    });
    var imageSrc =  "https://maps.googleapis.com/maps/api/staticmap?center=40.714728,-73.998672&zoom=12&size=400x400&maptype=satellite"; //+ "&key=" + YOUR_API_KEY
    mapImage.src = imageSrc;
  });
</script>
</body>
</html>

Ответ 3

Какую версию API карты Google вы используете?

Вы можете проверить это событие с помощью "playloaded".

Также есть событие, называемое "idle", которое вызывается, как только ваша карта находится в режиме ожидания.

Событие "idle" вызывается, когда карта переходит в состояние ожидания - все загружено полностью или что-то не так, и карта не загружается. Я думаю, что "простаивание" более надежно, а затем выгружено /bounds _changed и с помощью метода addListenerOnce код в закрытии выполняется при первом запуске "холостого хода", а затем событие отделяется.

Отметьте описание событий выше Ссылка