/* * This is part of Geomajas, a GIS framework, http://www.geomajas.org/. * * Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium. * * The program is available in open source according to the GNU Affero * General Public License. All contributions in this program are covered * by the Geomajas Contributors License Agreement. For full licensing * details, see LICENSE.txt in the project root. */ package org.geomajas.gwt.client.gfx.paintable.mapaddon; import java.util.ArrayList; import java.util.List; import org.geomajas.annotation.Api; import org.geomajas.configuration.client.ScaleInfo; import org.geomajas.gwt.client.controller.ZoomSliderController; import org.geomajas.gwt.client.gfx.PainterVisitor; import org.geomajas.gwt.client.gfx.paintable.Image; import org.geomajas.gwt.client.map.event.MapViewChangedEvent; import org.geomajas.gwt.client.map.event.MapViewChangedHandler; import org.geomajas.gwt.client.spatial.Bbox; import org.geomajas.gwt.client.widget.MapWidget; /** * A customizable zoom slider map add-on, which is always on top of other add-ons to make sure the * onDrag event of {@link ZoomSliderController} is not interrupted. * Using setters, you need to provide this class with; * <ul> * <li>{@link #setZoomIn(SingleMapAddon)}; This addon will be placed at the top of the slider.</li> * <li>{@link #setBackgroundPart(Image)}; image that represents one zoom level/scale in the background.</li> * <li>{@link #setSliderUnit(Image)}; image that represents the slider's unit or handle.</li> * <li>{@link #setZoomOut(SingleMapAddon)}; This addon will be placed at the bottom of the slider.</li> * </ul> * * @author Emiel Ackermann * @since 1.10.0 */ @Api public class ZoomSlider extends MapAddon implements MapViewChangedHandler { private Image backgroundPart; private Image sliderUnit; public static final String SLIDER = "slider"; public static final String SLIDER_UNIT = "sliderUnit"; public static final String SLIDER_AREA = "sliderArea"; private MapWidget mapWidget; private List<Double> currentScaleList = new ArrayList<Double>(); private SingleMapAddon zoomIn; private SliderArea sliderArea; private SingleMapAddon zoomOut; /** * A customizable zoom slider map add-on. Using setters, you need to provide this class with; * <ul> * <li>{@link #setZoomIn(SingleMapAddon)}; This addon will be placed at the top of the slider.</li> * <li>{@link #setBackgroundPart(Image)}; image that represents <b>one</b> zoom level/scale in the background.</li> * <li>{@link #setSliderUnit(Image)}; image that represents the slider's unit or handle.</li> * <li>{@link #setZoomOut(SingleMapAddon)}; This addon will be placed at the bottom of the slider.</li> * </ul> * * @param id id * @param mapWidget map widget */ public ZoomSlider(String id, MapWidget mapWidget) { super(id, 0, 0); this.mapWidget = mapWidget; } /** * Get the MapWidget object. * * @return the MapWidget object. */ public MapWidget getMapWidget() { return mapWidget; } /** * Get the SliderArea object. * * @return the SliderArea object. */ public SliderArea getSliderArea() { return sliderArea; } /** * Update the list of scales to include only the list of usable scales (from all possible scales). */ public void updateUsableScales() { Bbox bgBounds = backgroundPart.getBounds(); /* * First move background a little bit to right based on difference in width with the sliderUnit. */ int internalHorMargin = (int) (sliderUnit.getBounds().getWidth() - backgroundPart.getBounds().getWidth()) / 2; bgBounds.setX(internalHorMargin); int backgroundPartHeight = (int) bgBounds.getHeight(); int sliderAreaHeight = 0; /* * Needed for aligning the sliderUnit's y with currentScale's y. */ int currentUnitY = sliderAreaHeight; double currentScale = mapWidget.getMapModel().getMapView().getCurrentScale(); List<Bbox> partBounds = new ArrayList<Bbox>(); List<ScaleInfo> zoomLevels = mapWidget.getMapModel().getMapInfo().getScaleConfiguration().getZoomLevels(); int size = zoomLevels.size(); currentScaleList.clear(); boolean scaleFound = false; for (int i = size - 1 ; i >= 0 ; i--) { double scale = zoomLevels.get(i).getPixelPerUnit(); if (mapWidget.getMapModel().getMapView().isResolutionAvailable(1.0 / scale)) { Bbox bounds = (Bbox) bgBounds.clone(); bounds.setY(sliderAreaHeight); partBounds.add(bounds); currentScaleList.add(scale); if (scale <= currentScale && !scaleFound) { scaleFound = true; currentUnitY = sliderAreaHeight; } sliderAreaHeight += backgroundPartHeight; } } /* * Align zoom slider unit with current zoom */ Bbox bounds = sliderUnit.getBounds(); bounds.setY(currentUnitY); /* * Zoom slider area */ sliderArea = new SliderArea(SLIDER_AREA, (int) sliderUnit.getBounds().getWidth(), sliderAreaHeight, sliderUnit, backgroundPart, partBounds, mapWidget, new ZoomSliderController(this)); sliderArea.setHorizontalMargin((int) -bgBounds.getX()); sliderArea.setVerticalMargin((int) backgroundPart.getBounds().getWidth()); /* * Zoom out button internal margin. */ zoomOut.getBackground().getBounds().setY(sliderArea.getVerticalMargin() + sliderAreaHeight); zoomOut.getIcon().getBounds().setY(sliderArea.getVerticalMargin() + sliderAreaHeight); } @Override public void onMapViewChanged(MapViewChangedEvent event) { /** When the map size changes, update the usable scales and the background of the zoom slider. */ if (event.isMapResized()) { mapWidget.unregisterMapAddon(this); mapWidget.registerMapAddon(this); } if (!event.isSameScaleLevel()) { double currentScale = mapWidget.getMapModel().getMapView().getCurrentScale(); for (int i = 0 ; i < currentScaleList.size() ; i++) { double scale = currentScaleList.get(i); if (currentScale == scale) { Bbox bounds = sliderArea.getIcon().getBounds(); bounds.setY(i * backgroundPart.getBounds().getHeight()); sliderArea.drawImage(sliderArea.applyMargins(bounds)); } } } } /** * Get list of current scales. This list will be determined depending on map size and maximum bounds. * * @return list of current scales */ public List<Double> getCurrentScaleList() { return currentScaleList; } @Override public void accept(PainterVisitor visitor, Object group, Bbox bounds, boolean recursive) { mapWidget.getVectorContext().drawGroup(null, this); updateUsableScales(); zoomIn.accept(visitor, this, bounds, recursive); zoomOut.accept(visitor, this, bounds, recursive); //Draw area last to make sure its extended rectangle is always on top. sliderArea.accept(visitor, this, bounds, recursive); } @Override public void setMapSize(int mapWidth, int mapHeight) { super.setMapSize(mapWidth, mapHeight); zoomIn.setMapSize(mapWidth, mapHeight); zoomOut.setMapSize(mapWidth, mapHeight); } /** * Get the image object that is used for creating the background of the slider. * For each scale this image is used once. * * @return part of the background that represents one scale. */ public Image getBackgroundPart() { return backgroundPart; } /** * Set the image object that is used for creating the background of the slider. * For each scale this image is used once. * * @param part of the background that represents one scale. */ public void setBackgroundPart(Image backgroundPart) { this.backgroundPart = backgroundPart; } /** * Get the slider unit image object. * * @return the slider unit image object */ public Image getSliderUnit() { return sliderUnit; } /** * Set the slider unit image object. * * @param the slider unit image object */ public void setSliderUnit(Image sliderUnit) { this.sliderUnit = sliderUnit; } /** * Get the SingleMapAddon that zooms in. * * @return zoomOut SingleMapAddon that zooms in */ public SingleMapAddon getZoomIn() { return zoomIn; } /** * Set the SingleMapAddon that zooms in. * * @param zoomOut SingleMapAddon that zooms in */ public void setZoomIn(SingleMapAddon zoomIn) { this.zoomIn = zoomIn; } /** * Get the SingleMapAddon that zooms out. * * @return zoomOut SingleMapAddon that zooms out */ public SingleMapAddon getZoomOut() { return zoomOut; } /** * Set the SingleMapAddon that zooms out. * * @param zoomOut SingleMapAddon that zooms out */ public void setZoomOut(SingleMapAddon zoomOut) { this.zoomOut = zoomOut; } @Override public void onDraw() { } @Override public void onRemove() { } }