有沒有辦法來禁用谷歌地圖瓷磚的褪色?或者有沒有辦法檢測地圖是否完全呈現?
問題
我想獲得一個事件時,地圖完全加載(和渲染),並採取截圖。我想這些事件在幾個答案
google.maps.event.addListenerOnce(map, 'tilesloaded', function(){
// screenshot
});
google.maps.event.addListener(map, 'idle', function(){
// screenshot
});
window.onload = function(e){
// screenshot
};
建議,但瓷磚仍然褪色,即使在所有裝載和上述事件被解僱。
它看起來像這樣:左邊是谷歌地圖,右邊是採取事件發生後發射一個自動截圖:
代碼
的代碼是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
當然一個可以等待第二個,並採取截圖的話,但是這並不是一個妥善的解決辦法。
謝謝,但正如問題中所述,我希望有一個適當的解決方案,而不是猜測地圖可以完全加載和渲染。計時器不是一個選項。 – Roland
這是我必須解決的解決方案,因爲似乎沒有一個合適的解決方案。我認爲200ms的超時就足夠了。注意:在google api源代碼中有一個屬性「tileFadeMode」,但沒有關於它的描述,代碼被混淆了。 – Roland