Package org.geomajas.gwt.client.widget

Source Code of org.geomajas.gwt.client.widget.OverviewMap$MaxExtentHandler

/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2011 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.widget;

import org.geomajas.command.dto.GetMapConfigurationResponse;
import org.geomajas.geometry.Coordinate;
import org.geomajas.annotation.Api;
import org.geomajas.gwt.client.Geomajas;
import org.geomajas.gwt.client.controller.OverviewMapController;
import org.geomajas.gwt.client.gfx.paintable.GfxGeometry;
import org.geomajas.gwt.client.gfx.paintable.Image;
import org.geomajas.gwt.client.gfx.paintable.Rectangle;
import org.geomajas.gwt.client.gfx.style.ShapeStyle;
import org.geomajas.gwt.client.map.MapView;
import org.geomajas.gwt.client.map.event.MapModelEvent;
import org.geomajas.gwt.client.map.event.MapModelHandler;
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.spatial.WorldViewTransformer;
import org.geomajas.gwt.client.spatial.geometry.LinearRing;
import org.geomajas.gwt.client.spatial.geometry.Polygon;

import com.smartgwt.client.widgets.events.ResizedEvent;
import com.smartgwt.client.widgets.events.ResizedHandler;

/**
* MapWidget that listens to another MapWidget and shows an overview of it.
*
* @author Kristof Heirwegh
* @author Pieter De Graef
* @since 1.6.0
*/
@Api
public class OverviewMap extends MapWidget implements MapViewChangedHandler {

  private static final String TARGET_RETICLE_IMAGE = "geomajas/widget/target.gif";

  /** Reference to the main map, that this overview map is to follow. */
  private MapWidget targetMap;

  /** Should the overview map zoom in/out according to targetMap? */
  private boolean dynamicOverview = true;

  private Rectangle targetRectangle;

  private GfxGeometry targetMaxExtentRectangle;

  private Image targetReticle;

  private ShapeStyle rectangleStyle;

  private ShapeStyle targetMaxExtentRectangleStyle;

  /**
   * Use the max extent to boot up this overview map (true), or use the default initial bounds from the configuration
   * (false). The map extent is calculated from the map's layers.
   */
  private boolean useTargetMaxExtent;

  private int maxExtentIncreasePercentage = 5;

  /** Draw the borders of the target map's maximum extent? */
  private boolean drawTargetMaxExtent;

  /**
   * Constructor the an overview map. The scale bar, panning buttons and zoomOnScroll are automatically disabled. Also
   * a {@link OverviewMapController} is automatically set.
   *
   * @param id
   *            Overview map ID from the configurations. Will also be use as widget id.
   * @param applicationId
   *            This application's unique identifier. Must resemble an ID from the XML configurations, so it can
   *            initialize itself.
   * @param targetMap
   *            Reference to the main map, that this overview map has to follow.
   * @param useTargetMaxExtent
   *            Use the max extent to boot up this overview map (true), or use the default initial bounds from the
   *            configuration (false).
   * @param drawTargetMaxExtent
   *            Draw the borders of the target map's maximum extent?
   * @since 1.8.0
   */
  @Api
  public OverviewMap(String id, String applicationId, MapWidget targetMap, boolean useTargetMaxExtent,
      boolean drawTargetMaxExtent) {
    super(id, applicationId);
    if (null == targetMap) {
      throw new IllegalArgumentException("Please provide a targetmap");
    }
    this.targetMap = targetMap;
    this.useTargetMaxExtent = useTargetMaxExtent;
    this.drawTargetMaxExtent = drawTargetMaxExtent;
    targetMap.getMapModel().getMapView().addMapViewChangedHandler(new UpdatePointOfViewHandler());
    scaleBarEnabled = false;
    navigationAddonEnabled = false;
    rectangleStyle = new ShapeStyle("#FF9900", 0.2f, "#FF9900", 1f, 2);
    targetMaxExtentRectangleStyle = new ShapeStyle("#555555", 0.4f, "#555555", 1f, 1);
    setZoomOnScrollEnabled(false);
    // handle max extent when both maps are loaded
    MaxExtentHandler meh = new MaxExtentHandler();
    getMapModel().addMapModelHandler(meh);
    targetMap.getMapModel().addMapModelHandler(meh);
    // handle max extent on resize
    addResizedHandler(new ResizedHandler() {

      public void onResized(ResizedEvent event) {
        updateMaxExtent();
      }
    });
  }

  /**
   * Constructor the an overview map. The scale bar, panning buttons and zoomOnScroll are automatically disabled. Also
   * a {@link OverviewMapController} is automatically set.
   *
   * @param id
   *            Overview map ID from the configurations. Will also be use as widget id.
   * @param applicationId
   *            This application's unique identifier. Must resemble an ID from the XML configurations, so it can
   *            initialize itself.
   * @param targetMap
   *            Reference to the main map, that this overview map has to follow.
   * @param useTargetMaxExtent
   *            Use the max extent to boot up this overview map (true), or use the default initial bounds from the
   *            configuration (false).
   * @param drawTargetMaxExtent
   *            Draw the borders of the target map's maximum extent?
   * @param maxExtentIncreasePercentage
   *            Percentage of border which should be displayed around the max extent in the overview map.
   * @since 1.8.0
   */
  @Api
  public OverviewMap(String id, String applicationId, MapWidget targetMap, boolean useTargetMaxExtent,
      boolean drawTargetMaxExtent, int maxExtentIncreasePercentage) {
    this(id, applicationId, targetMap, useTargetMaxExtent, drawTargetMaxExtent);
    setMaxExtentIncreasePercentage(maxExtentIncreasePercentage);
  }

  // ------------------------------------------------------------------------
  // Public methods:
  // ------------------------------------------------------------------------

  public MapWidget getTargetMap() {
    return targetMap;
  }

  public boolean isDynamicOverview() {
    return dynamicOverview;
  }

  /**
   * Should the overview map zoom in/out according to targetMap?
   *
   * @param dynamicOverview
   *            true when overview map needs to zoom in/out with target map
   */
  public void setDynamicOverview(boolean dynamicOverview) {
    this.dynamicOverview = dynamicOverview;
  }

  /**
   * Move the Point of view (rectangle or reticle) to a new location. This does not update the target map!
   *
   * @param deltaX
   *            horizontal amount the pov should be moved from current location: screen view coordinate!
   * @param deltaY
   *            vertical amount the pov should be moved from current location: screen view coordinate!
   */
  public void movePov(double deltaX, double deltaY) {
    if (null != targetRectangle) {
      targetRectangle.getBounds().translate(deltaX, deltaY);
      render(targetRectangle, RenderGroup.SCREEN, RenderStatus.UPDATE);

    } else if (null != targetReticle) {
      targetReticle.getBounds().translate(deltaX, deltaY);
      render(targetReticle, RenderGroup.SCREEN, RenderStatus.UPDATE);
    }
    // else not initialized
  }

  /**
   * Pan the target map to a new location.
   * <p>
   * You do not need to use movePov(), this will be done through the event-listener.
   *
   * @param deltaX
   *            horizontal amount the target map should be moved from current location: world view coordinate!
   * @param deltaY
   *            vertical amount the target map should be moved from current location: world view coordinate!
   */
  public void panTargetMap(double deltaX, double deltaY) {
    targetMap.getMapModel().getMapView().translate(deltaX, deltaY);
  }

  // ------------------------------------------------------------------------
  // Getters and setters:
  // ------------------------------------------------------------------------

  /**
   * Set the percentage to increase the map maxExtent.
   *
   * @param maxExtentIncreasePercentage
   *            presentage to increase the maxExtent
   * @since 1.8.0
   */
  @Api
  public void setMaxExtentIncreasePercentage(int maxExtentIncreasePercentage) {
    this.maxExtentIncreasePercentage = maxExtentIncreasePercentage;
  }

  public ShapeStyle getRectangleStyle() {
    return rectangleStyle;
  }

  /**
   * Set a new style for the rectangle that shows the current position on the target map.
   *
   * @param rectangleStyle
   *            rectangle style
   * @since 1.8.0
   */
  @Api
  public void setRectangleStyle(ShapeStyle rectangleStyle) {
    this.rectangleStyle = rectangleStyle;
    if (targetRectangle != null) {
      targetRectangle.setStyle(rectangleStyle);
      render(targetRectangle, RenderGroup.SCREEN, RenderStatus.ALL);
    }
  }

  public boolean isDrawTargetMaxExtent() {
    return drawTargetMaxExtent;
  }

  /**
   * Determine whether or not a rectangle that shows the target map's maximum extent should be shown.
   *
   * @param drawTargetMaxExtent
   *            should the max extent be marked on the map?
   * @since 1.8.0
   */
  @Api
  public void setDrawTargetMaxExtent(boolean drawTargetMaxExtent) {
    this.drawTargetMaxExtent = drawTargetMaxExtent;

    // Immediately draw or remove the max extent rectangle:
    if (drawTargetMaxExtent) {
      targetMaxExtentRectangle = new GfxGeometry("targetMaxExtentRectangle");
      targetMaxExtentRectangle.setStyle(targetMaxExtentRectangleStyle);

      Bbox targetMaxExtent = getOverviewMaxBounds();

      Bbox box = getMapModel().getMapView().getWorldViewTransformer().worldToView(targetMaxExtent);
      LinearRing shell = getMapModel().getGeometryFactory().createLinearRing(
          new Coordinate[] { new Coordinate(-2, -2), new Coordinate(getWidth() + 2, -2),
              new Coordinate(getWidth() + 2, getHeight() + 2), new Coordinate(-2, getHeight() + 2) });
      LinearRing hole = getMapModel().getGeometryFactory().createLinearRing(
          new Coordinate[] { new Coordinate(box.getX(), box.getY()),
              new Coordinate(box.getMaxX(), box.getY()), new Coordinate(box.getMaxX(), box.getMaxY()),
              new Coordinate(box.getX(), box.getMaxY()) });
      Polygon polygon = getMapModel().getGeometryFactory().createPolygon(shell, new LinearRing[] { hole });
      targetMaxExtentRectangle.setGeometry(polygon);
      render(targetMaxExtentRectangle, RenderGroup.SCREEN, RenderStatus.ALL);
    } else {
      render(targetMaxExtentRectangle, RenderGroup.SCREEN, RenderStatus.DELETE);
      targetMaxExtentRectangle = null;
    }
  }

  public ShapeStyle getTargetMaxExtentRectangleStyle() {
    return targetMaxExtentRectangleStyle;
  }

  /**
   * Set a new style for the rectangle that show the target map's maximum extent. This style will be applied
   * immediately.
   *
   * @param targetMaxExtentRectangleStyle
   *            max extent marker rectangle style
   * @since 1.8.0
   */
  @Api
  public void setTargetMaxExtentRectangleStyle(ShapeStyle targetMaxExtentRectangleStyle) {
    this.targetMaxExtentRectangleStyle = targetMaxExtentRectangleStyle;
    if (targetMaxExtentRectangle != null) {
      targetMaxExtentRectangle.setStyle(targetMaxExtentRectangleStyle);
      if (drawTargetMaxExtent) {
        render(targetMaxExtentRectangle, RenderGroup.SCREEN, RenderStatus.UPDATE);
      }
    }
  }

  // ------------------------------------------------------------------------
  // Private methods:
  // ------------------------------------------------------------------------

  /**
   * Override the initialize method, to set a controller, and perhaps apply the target map's max extent.
   */
  @Override
  protected void initializationCallback(GetMapConfigurationResponse r) {
    super.initializationCallback(r);
    setController(new OverviewMapController(this));
    updateMaxExtent();
  }

  /**
   * Apply a maximum extent. This will extend the map extend to be used by the percentage to increase.
   */
  private void updateMaxExtent() {
    if (targetMap.getMapModel().isInitialized()) {
      Bbox targetMaxBounds = getOverviewMaxBounds();

      MapView mapView = getMapModel().getMapView();

      // Set the maxBounds on this map as well:
      mapView.setMaxBounds(targetMaxBounds.buffer(targetMaxBounds.getWidth()));

      // apply buffer
      if (maxExtentIncreasePercentage > 0) {
        targetMaxBounds = targetMaxBounds
            .buffer(targetMaxBounds.getWidth() * maxExtentIncreasePercentage / 100);
      }

      // Then apply the map extent:
      mapView.applyBounds(targetMaxBounds, MapView.ZoomOption.LEVEL_FIT);
      super.onMapViewChanged(null);

      // Immediately draw or remove the max extent rectangle:
      setDrawTargetMaxExtent(drawTargetMaxExtent);
    }
  }

  /**
   * Update the rectangle, and perhaps the entire map if needed.
   */
  private void updatePov() {
    MapView mapView = getMapModel().getMapView();
    WorldViewTransformer transformer = new WorldViewTransformer(mapView);
    Bbox targetBox = targetMap.getMapModel().getMapView().getBounds();
    Bbox overviewBox = mapView.getBounds();

    // check if bounds are valid
    if (Double.isNaN(overviewBox.getX())) {
      return;
    }

    // zoom if current view is too small
    if (dynamicOverview && !overviewBox.contains(targetBox)) {
      // mapView.applyBounds(overviewBox.union(targetBox), MapView.ZoomOption.LEVEL_FIT);
      // super.onMapViewChanged(null);
    }

    // calculate boxSize
    Coordinate viewBegin = transformer.worldToView(targetBox.getOrigin());
    Coordinate viewEnd = transformer.worldToView(targetBox.getEndPoint());

    double width = Math.abs(viewEnd.getX() - viewBegin.getX());
    double height = Math.abs(viewEnd.getY() - viewBegin.getY());
    viewBegin.setY(viewBegin.getY() - height);

    // show recticle or box
    if (width < 20) {
      if (null != targetRectangle) {
        render(targetRectangle, RenderGroup.SCREEN, RenderStatus.DELETE);
        targetRectangle = null;
      }
      if (null == targetReticle) {
        targetReticle = new Image("targetReticle");
        targetReticle.setHref(Geomajas.getIsomorphicDir() + TARGET_RETICLE_IMAGE);
        targetReticle.setBounds(new Bbox(0, 0, 21, 21));
      }
      double x = viewBegin.getX() + (width / 2) - 10;
      double y = viewBegin.getY() + (width / 2) - 10;
      targetReticle.getBounds().setX(x);
      targetReticle.getBounds().setY(y);
      render(targetReticle, RenderGroup.SCREEN, RenderStatus.UPDATE);

    } else {
      if (null != targetReticle) {
        render(targetReticle, RenderGroup.SCREEN, RenderStatus.DELETE);
        targetReticle = null;
      }
      if (null == targetRectangle) {
        targetRectangle = new Rectangle("targetRect");
        targetRectangle.setStyle(rectangleStyle);
      }
      targetRectangle.setBounds(new Bbox(viewBegin.getX(), viewBegin.getY(), width, height));
      render(targetRectangle, RenderGroup.SCREEN, RenderStatus.UPDATE);
    }
  }

  /**
   * The maximum bounds depend on whether useTargetMaxExtent was set. If not set, the initialBounds from the
   * overviewMap are used. It it was set the maximum bounds of the target view is used.
   *
   * @return maxBounds for overview map
   */
  private Bbox getOverviewMaxBounds() {
    Bbox targetMaxBounds;
    if (!useTargetMaxExtent) {
      targetMaxBounds = new Bbox(getMapModel().getMapInfo().getInitialBounds());
    } else {
      // maxBounds was not configured, or need to use maxBounds from target
      if (targetMap.getMapModel().isInitialized()) {
        // rely on target map bounds
        targetMaxBounds = targetMap.getMapModel().getMapView().getMaxBounds();
      } else {
        // fall back to configured bounds (should be temporary)
        targetMaxBounds = new Bbox(targetMap.getMapModel().getMapInfo().getMaxBounds());
      }
    }
    return targetMaxBounds;
  }

  /**
   * Updates the max extent when both maps are ready to go.
   *
   * @author Jan De Moerloose
   *
   */
  private class MaxExtentHandler implements MapModelHandler {

    private boolean targetMapDone;

    private boolean overviewMapDone;

    public void onMapModelChange(MapModelEvent event) {
      if (event.getSource() == getMapModel()) {
        overviewMapDone = true;
      } else if (event.getSource() == targetMap.getMapModel()) {
        targetMapDone = true;
      }
      if (targetMapDone && overviewMapDone) {
        updateMaxExtent();
      }
    }

  }

  /**
   * Updates the point of view of the overview map when the main map's view changes.
   *
   * @author Jan De Moerloose
   *
   */
  private class UpdatePointOfViewHandler implements MapViewChangedHandler {

    public void onMapViewChanged(MapViewChangedEvent event) {
      updatePov();
    }

  }

}
TOP

Related Classes of org.geomajas.gwt.client.widget.OverviewMap$MaxExtentHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
-20639858-1', 'auto'); ga('send', 'pageview');