问题
有没有办法禁用Google地图图块的淡化?或者有没有办法检测地图是否完全渲染?
问题
我想在地图完全加载(和渲染)时获取一个事件并截取屏幕截图。我按照几个答案中的建议尝试了这些事件
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: javafx.scene.web.WebEngine$LoadWorker@6954b271, name: state, value: SCHEDULED]
Webpage loaded
Latitude = 38.897676, Longitude = -77.036483
[Running] true
[State] ReadOnlyObjectProperty [bean: javafx.scene.web.WebEngine$LoadWorker@6954b271, 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: javafx.scene.web.WebEngine$LoadWorker@6954b271, name: state, value: SUCCEEDED]
[Running] false
[javascript] tilesloaded
[javascript] onMapLoadingFinished
taking screenshot
当然可以等一下然后再截取屏幕截图,但这不是一个合适的解决方案。
答案 0 :(得分:3)
谷歌地图事件非常独立。即使地图可能正在平移,tilesloaded
听众也会特别开火。通过尝试在此侦听器示例中here施加压力地图,可以看出这一点。{/ p>
此外,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);
});
答案 1 :(得分:3)
我无法找到确定地图何时完全加载的方法,但您可以首先使用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>
答案 2 :(得分:2)
您使用的Google地图API版本是什么?
您可以查看&#34; tilesloaded&#34;事件
还有一个名为&#34; idle&#34;一旦你的地图处于闲置状态,它就会被调用。
&#34;空闲&#34;当地图进入空闲状态时调用事件 - 完全加载所有内容或发生错误并且映射无法加载。 我认为&#34;闲置&#34;比tilesload / bounds_changed更可靠,并且使用addListenerOnce方法,闭包中的代码第一次执行&#34; idle&#34;被解雇然后分离事件。
在Link
检查有关上述事件的说明