Hi ,
I am trying to develop zooControls like zoomIn and zoomOut. i give below the code about zoomIn and ZoomOut.
public void zoomIn() {
double x, y;
x= mapView.getScaleX();
y= mapView.getScaleY();
mapView.setScaleX(x+1);
mapView.setScaleY(y+1);
}
public void zoomOut() {
double x, y;
x= mapView.getScaleX();
y= mapView.getScaleY();
mapView.setScaleX(x-1);
mapView.setScaleY(y-1);
}
but the problem is when i click zoomIn button the mapview is overlaping with other pane and when i click zoomOut , it is not working and mapview is not zoomout within its stackpane like mouse's zoomIn and zoomout. i attach some code snippet.
For my map application, changes zoom level of map by +1 or -1 and default minimum zoom level is 0, default maximum zoom level is 18.
so , there is another way to work with directly with mapview's zoom level?? above code is not working like mouse's zooming. can you guys give recommendation how to solve this problem?
Hi,
The methods that you are trying to to use on the MapView refer to JavaFX scaling - literally scaling the size of the control.
You can zoom the map by changing the ViewPoint as shown below.
Button zoomIn = new Button("Zoom in");
Button zoomOut = new Button("Zoom out");
zoomIn.setOnAction(a -> {
Viewpoint current = mapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE);
Viewpoint zoomedIn = new Viewpoint((Point) current.getTargetGeometry(), current.getTargetScale() / 2.0);
mapView.setViewpointAsync(zoomedIn);
});
zoomOut.setOnAction(a -> {
Viewpoint current = mapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE);
Viewpoint zoomedOut = new Viewpoint((Point) current.getTargetGeometry(), current.getTargetScale() * 2.0);
mapView.setViewpointAsync(zoomedOut);
});
Hi,
your hint is nicely working. but how can i implement that zoomlevel max 18 and zoomlevel min 0?
You can access the scale for each LOD something like
var tiledLayer = new ArcGISTiledLayer("http://services.arcgisonline.com/arcgis/rest/services/World_Topo_Map/MapServer");
tiledLayer.addDoneLoadingListener(() -> {
var lods = tiledLayer.getTileInfo().getLevelsOfDetail();
lods.forEach(lod -> System.out.println(lod.getScale()));
});
and use the scale in the zoom in/zoom out buttons.
Hello,
thank you for the helpful reply . i am still facing confusion that for zoom control . i explain now little bit why i need zoom level , for map application max zoom level will be 18 and when zoom level going 18 or 18 plus the zoomln button will be disable .for also zoomOut when zoomlevel 0 (min) will be reached then zoomOut button will be disable . for those i need to work with some how zoomlevel 18 and 0 for respective max and min and disable those two button on those two zoomlevel respectively. i am using Wmslayer Class in my map application.
//zoomIn Button
public void zoomIn(ActionEvent event) {
map.zoomControl(true) ;
}
//zoomOut Button
public void zoomOut(ActionEvent event) {
map.zoomControl(false);
}
//zoomControl method
public void zoomControl(boolean zoom) {
if(zoom == true) {
Viewpoint current = mapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE);
Viewpoint zoomedIn = new Viewpoint((Point) current.getTargetGeometry(),
current.getTargetScale() / 2.0);
mapView.setViewpointAsync(zoomedIn);
}else {
Viewpoint current = mapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE);
Viewpoint zoomedOut = new Viewpoint((Point) current.getTargetGeometry(),
current.getTargetScale() * 2.0);
mapView.setViewpointAsync(zoomedOut);
}
}
I think you can do this by setting the min and max scales the the appropriate levels of detail e.g.
tiledLayer.setMinScale(lods.get(0).getScale());
tiledLayer.setMaxScale(lods.get(18).getScale());
Hi,
I implement your idea . but it doesnt disable the button. can you help me to sort out where i am doing wrong ??
//zoomIn Button
public void zoomIn(ActionEvent event) {
map.zoomControl(true) ;
}
//zoomOut Button
public void zoomOut(ActionEvent event) {
map.zoomControl(false);
}
//zoomControl method
public void zoomControl(boolean zoom) {
var lods = tiledLayer.getTileInfo().getLevelsOfDetail();
tiledLayer.setMaxScale(lods.get(18).getScale());
tiledLayer.setMinScale(lods.get(0).getScale());
if(zoom == true) {
Viewpoint current = mapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE);
Viewpoint zoomedIn = new Viewpoint((Point) current.getTargetGeometry(),
current.getTargetScale() / 2.0);
mapView.setViewpointAsync(zoomedIn);
if (this.equals(tiledLayer.getMaxScale())) {
zoomIn.setDisable(true);
}
}
else {
Viewpoint current = mapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE);
Viewpoint zoomedOut = new Viewpoint((Point) current.getTargetGeometry(),
current.getTargetScale() * 2.0);
mapView.setViewpointAsync(zoomedOut);
if (this.equals(tiledLayer.getMinScale())) {
zoomIn.setDisable(true);
}
}
}
mapView.setViewpointAsync(zoomedIn) is an async call so you would have to add a done listener if you want to take action when the new scale is reached since it doesn’t happen immediately so something like
mapView.setViewpointAsync(zoomedIn).addDoneListener(() -> {
// check to see if zoom in or zoom out should be disabled/enabled
});
An alternative would be to add a listener for scale changes on the MapView. As an example the following would disable the zoom in when you reach LOD 18 but otherwise enable the button.
mapView.addMapScaleChangedListener(s -> zoomIn.setDisable(mapView.getMapScale() <= lods.get(18).getScale()));
i used your alternative apporach . but i get exception
public void zoomControl(boolean zoom) {
var lods = tiledLayer.getTileInfo().getLevelsOfDetail();
tiledLayer.setMaxScale(lods.get(18).getScale());
tiledLayer.setMinScale(lods.get(0).getScale());
double MaxZoomLevel = tiledLayer.getMaxScale();
double MinZoomLevel = tiledLayer.getMinScale();
//zoomIn.setDisable(false);
//zoomOut.setDisable(false);
if(zoom == true) {
Viewpoint current = mapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE);
Viewpoint zoomedIn = new Viewpoint((Point) current.getTargetGeometry(),
current.getTargetScale() / 2.0);
mapView.setViewpointAsync(zoomedIn);
mapView.addMapScaleChangedListener(s -> zoomIn.setDisable(mapView.getMapScale() <= lods.get(18).getScale()));
}
else {
Viewpoint current = mapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE);
Viewpoint zoomedOut = new Viewpoint((Point) current.getTargetGeometry(),
current.getTargetScale() * 2.0);
mapView.setViewpointAsync(zoomedOut);
mapView.addMapScaleChangedListener(s -> zoomOut.setDisable(mapView.getMapScale() >= lods.get(0).getScale()));
}
}
==============================================================================
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at iJMSFx/application.IJMSMap.lambda$1(IJMSMap.java:166)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.MapScaleChangedListenerRunnerImpl.run(MapScaleChangedListenerRunnerImpl.java:51)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.MapViewImpl$2.scaleChanged(MapViewImpl.java:101)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.jni.CoreMapView.onScaleChanged(CoreMapView.java:366)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.RenderingContext.nativePulse(Native Method)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.RenderingContext.pulse(RenderingContext.java:97)
at java.base/java.util.concurrent.CopyOnWriteArrayList.forEach(CopyOnWriteArrayList.java:803)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.PulseThread$1.handle(PulseThread.java:31)
at javafx.graphics/javafx.animation.AnimationTimer$AnimationTimerReceiver.lambda$handle$0(AnimationTimer.java:57)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
at javafx.graphics/javafx.animation.AnimationTimer$AnimationTimerReceiver.handle(AnimationTimer.java:56)
at javafx.graphics/com.sun.scenario.animation.AbstractMasterTimer.timePulseImpl(AbstractMasterTimer.java:357)
at javafx.graphics/com.sun.scenario.animation.AbstractMasterTimer$MainLoop.run(AbstractMasterTimer.java:267)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:515)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:499)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:492)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:320)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
at java.base/java.lang.Thread.run(Thread.java:835)
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at iJMSFx/application.IJMSMap.lambda$1(IJMSMap.java:166)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.MapScaleChangedListenerRunnerImpl.run(MapScaleChangedListenerRunnerImpl.java:51)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.MapViewImpl$2.scaleChanged(MapViewImpl.java:101)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.jni.CoreMapView.onScaleChanged(CoreMapView.java:366)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.RenderingContext.nativePulse(Native Method)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.RenderingContext.pulse(RenderingContext.java:97)
at java.base/java.util.concurrent.CopyOnWriteArrayList.forEach(CopyOnWriteArrayList.java:803)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.PulseThread$1.handle(PulseThread.java:31)
at javafx.graphics/javafx.animation.AnimationTimer$AnimationTimerReceiver.lambda$handle$0(AnimationTimer.java:57)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
at javafx.graphics/javafx.animation.AnimationTimer$AnimationTimerReceiver.handle(AnimationTimer.java:56)
at javafx.graphics/com.sun.scenario.animation.AbstractMasterTimer.timePulseImpl(AbstractMasterTimer.java:357)
at javafx.graphics/com.sun.scenario.animation.AbstractMasterTimer$MainLoop.run(AbstractMasterTimer.java:267)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:515)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:499)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:492)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:320)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
at java.base/java.lang.Thread.run(Thread.java:835)
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at iJMSFx/application.IJMSMap.lambda$1(IJMSMap.java:166)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.MapScaleChangedListenerRunnerImpl.run(MapScaleChangedListenerRunnerImpl.java:51)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.MapViewImpl$2.scaleChanged(MapViewImpl.java:101)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.jni.CoreMapView.onScaleChanged(CoreMapView.java:366)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.RenderingContext.nativePulse(Native Method)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.RenderingContext.pulse(RenderingContext.java:97)
at java.base/java.util.concurrent.CopyOnWriteArrayList.forEach(CopyOnWriteArrayList.java:803)
at com.esri.arcgisruntime/com.esri.arcgisruntime.internal.mapping.view.PulseThread$1.handle(PulseThread.java:31)
at javafx.graphics/javafx.animation.AnimationTimer$AnimationTimerReceiver.lambda$handle$0(AnimationTimer.java:57)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
at javafx.graphics/javafx.animation.AnimationTimer$AnimationTimerReceiver.handle(AnimationTimer.java:56)
at javafx.graphics/com.sun.scenario.animation.AbstractMasterTimer.timePulseImpl(AbstractMasterTimer.java:357)
at javafx.graphics/com.sun.scenario.animation.AbstractMasterTimer$MainLoop.run(AbstractMasterTimer.java:267)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:515)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:499)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:492)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:320)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
at java.base/java.lang.Thread.run(Thread.java:835)
I think maybe you are adding the MapView scale listener in the wrong place. Try something like this which should disable the zoom in once you reach LOD 18 and enable it if you zoom back out…
import com.esri.arcgisruntime.geometry.Point;
import com.esri.arcgisruntime.layers.ArcGISTiledLayer;
import com.esri.arcgisruntime.mapping.ArcGISMap;
import com.esri.arcgisruntime.mapping.Basemap;
import com.esri.arcgisruntime.mapping.Viewpoint;
import com.esri.arcgisruntime.mapping.view.MapView;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class App extends Application {
MapView mapView = new MapView();
@Override
public void start(Stage stage) throws Exception {
Platform.setImplicitExit(true);
var borderPane = new BorderPane();
var scene = new Scene(borderPane);
stage.setScene(scene);
stage.setWidth(500);
stage.setHeight(500);
stage.show();
var map = new ArcGISMap();
var tiledLayer = new ArcGISTiledLayer("http://services.arcgisonline.com/arcgis/rest/services/World_Topo_Map/MapServer");;
tiledLayer.addDoneLoadingListener(() -> {
var lods = tiledLayer.getTileInfo().getLevelsOfDetail();
lods.forEach(lod -> System.out.println(lod.getLevel() + " " + lod.getScale() + " " + lod.getResolution()));
//tiledLayer.setMinScale(lods.get(0).getScale());
//tiledLayer.setMaxScale(lods.get(18).getScale());
HBox box = new HBox();
borderPane.setBottom(box);
Button zoomIn = new Button("Zoom in");
Button zoomOut = new Button("Zoom out");
zoomIn.setOnAction(a -> {
Viewpoint current = mapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE);
Viewpoint zoomedIn = new Viewpoint((Point) current.getTargetGeometry(), current.getTargetScale() / 2.0);
});
zoomOut.setOnAction(a -> {
Viewpoint current = mapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE);
Viewpoint zoomedOut = new Viewpoint((Point) current.getTargetGeometry(), current.getTargetScale() * 2.0);
mapView.setViewpointAsync(zoomedOut);
});
box.getChildren().addAll(zoomIn, zoomOut);
mapView.addMapScaleChangedListener(s -> zoomIn.setDisable(mapView.getMapScale() <= lods.get(18).getScale()));
});
Basemap basemap = new Basemap();
basemap.getBaseLayers().add(tiledLayer);
map.setBasemap(basemap);
mapView.setMap(map);
borderPane.setCenter(mapView);
}
@Override
public void stop() throws Exception {
if (mapView != null) {
mapView.dispose();
}
}
public static void main(String[] args) {
launch(args);
}
}