com.moesol.gwt.maps.client.controls.MapPanZoomControl.java Source code

Java tutorial

Introduction

Here is the source code for com.moesol.gwt.maps.client.controls.MapPanZoomControl.java

Source

/**
 * (c) Copyright, Moebius Solutions, Inc., 2012
 *
 *                        All Rights Reserved
 *
 * LICENSE: GPLv3
 */
package com.moesol.gwt.maps.client.controls;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Widget;
import com.moesol.gwt.maps.client.MapView;

/**
 * Control for panning and zooming the map.
 */
public class MapPanZoomControl extends Composite {

    // encapsulates code testable with regular JUnit tests
    // TODO: move more testable code here.
    static class Presenter {
        double calculateDelta(int panButtonDimension, int eventRelativeCoord, int maxPanPixels) {
            final double halfPanButtonDimension = panButtonDimension / 2.0;

            return ((eventRelativeCoord / halfPanButtonDimension) - 1.0) * maxPanPixels;
        }
    }

    private static MapPanZoomControlUiBinder uiBinder = GWT.create(MapPanZoomControlUiBinder.class);

    interface MapPanZoomControlUiBinder extends UiBinder<Widget, MapPanZoomControl> {
    }

    private Presenter m_presenter = new Presenter();

    private MapView m_map;
    private boolean m_doingMapAction = false;

    private int m_maxPanPixels;
    private int m_millisBetweenConsecutiveActions;

    @UiField
    DivElement clickHighlight;

    @UiField
    HTML zoomInButton;

    @UiField
    HTML zoomOutButton;

    private Timer m_panButtonTimer = new Timer() {
        @Override
        public void run() {
            m_map.moveMapByPixels((int) m_dx, (int) m_dy);
        }
    };

    private Timer m_zoomInButtonTimer = new Timer() {
        @Override
        public void run() {
            m_map.zoomByFactor(1.05);
        }
    };

    private Timer m_zoomOutButtonTimer = new Timer() {
        @Override
        public void run() {
            // 0.952380952 = 1/1.05
            m_map.zoomByFactor(0.952380952);
        }
    };

    private boolean m_panning;

    /**
     * @param map The map to plug this control into.
     * @param maxPanPixels The maximum number of pixels to
     * move the map each time a pan occurs. 
     * @param millisBetweenPans The milliseconds between consecutive
     * pans that occur while the mouse is down on the pan portion
     * of the control.
     */
    public void initPanVals(int maxPanPixels, int millisBetweenPans) {
        m_maxPanPixels = maxPanPixels;
        m_millisBetweenConsecutiveActions = millisBetweenPans;
    }

    public void setMapView(MapView map) {
        m_map = map;
    }

    public MapPanZoomControl() {
        initWidget(uiBinder.createAndBindUi(this));
    }

    /**
     * @param map The map to plug this control into.
     * @param maxPanPixels The maximum number of pixels to
     * move the map each time a pan occurs. 
     * @param millisBetweenPans The milliseconds between consecutive
     * pans that occur while the mouse is down on the pan portion
     * of the control.
     */
    public MapPanZoomControl(MapView map, int maxPanPixels, int millisBetweenPans) {
        m_map = map;
        m_maxPanPixels = maxPanPixels;
        m_millisBetweenConsecutiveActions = millisBetweenPans;
        initWidget(uiBinder.createAndBindUi(this));
    }

    @UiHandler("panButton")
    public void onPanButtonMouseUp(MouseUpEvent e) {
        e.preventDefault();
        stopPanLoop();
    }

    @UiHandler("panButton")
    public void onPanButtonMouseOut(MouseOutEvent e) {
        e.preventDefault();
        stopPanLoop();
    }

    @UiHandler("panButton")
    public void onPanButtonMouseDown(MouseDownEvent e) {
        e.preventDefault();
        updateVelocity(e);
        startPanLoop();
    }

    @UiHandler("panButton")
    public void onPanButtonMouseMove(MouseMoveEvent e) {
        e.preventDefault();
        if (m_panning) {
            updateVelocity(e);
        }
    }

    @UiField
    HTML panButton;

    private double m_dx;

    private double m_dy;

    @SuppressWarnings("rawtypes")
    private void updateVelocity(MouseEvent e) {
        int eventRelativeX = e.getRelativeX(panButton.getElement());
        int eventRelativeY = e.getRelativeY(panButton.getElement());

        final int panButtonWidth = panButton.getOffsetWidth();
        final int panButtonHeight = panButton.getOffsetHeight();

        if (eventRelativeX > 0 && eventRelativeX < panButtonWidth && eventRelativeY > 0
                && eventRelativeY < panButtonHeight) {
            final Style clickHighlightStyle = clickHighlight.getStyle();
            clickHighlightStyle.setDisplay(Display.BLOCK);
            clickHighlightStyle.setLeft(eventRelativeX - (clickHighlight.getClientWidth() / 3), Unit.PX);
            clickHighlightStyle.setTop(eventRelativeY - (clickHighlight.getClientHeight() / 3), Unit.PX);

            m_dx = m_presenter.calculateDelta(panButtonWidth, eventRelativeX, m_maxPanPixels);
            m_dy = -m_presenter.calculateDelta(panButtonHeight, eventRelativeY, m_maxPanPixels);
        }
    }

    private void startPanLoop() {
        m_panning = true;
        m_panButtonTimer.run();
        m_panButtonTimer.scheduleRepeating(m_millisBetweenConsecutiveActions);
    }

    private void stopPanLoop() {
        final Style clickHighlightStyle = clickHighlight.getStyle();
        clickHighlightStyle.setDisplay(Display.NONE);
        m_panning = false;
        m_panButtonTimer.cancel();
    }

    @UiHandler("zoomInButton")
    public void onZoomInButtonMouseDown(MouseDownEvent e) {
        e.preventDefault();
        resetStyleNamesTo(zoomInButton, true, "map-PanZoomControlZoomInButtonMouse");
        startZoomLoop(m_zoomInButtonTimer);
    }

    private void startZoomLoop(Timer zoomTimer) {
        m_doingMapAction = true;
        zoomTimer.run();
        zoomTimer.scheduleRepeating(m_millisBetweenConsecutiveActions);
    }

    @UiHandler("zoomInButton")
    public void onZoomInButtonMouseUp(MouseUpEvent e) {
        e.preventDefault();
        resetStyleNamesTo(zoomInButton, true, "map-PanZoomControlZoomInButtonMouseOver");
        stopZoomLoop(m_zoomInButtonTimer);
    }

    private void stopZoomLoop(Timer zoomTimer) {
        zoomTimer.cancel();
        if (m_doingMapAction) {
            m_doingMapAction = false;
            m_map.updateView();
        }
    }

    @UiHandler("zoomInButton")
    public void onZoomInButtonMouseOver(MouseOverEvent e) {
        e.preventDefault();
        resetStyleNamesTo(zoomInButton, true, "map-PanZoomControlZoomInButtonMouseOver");
        stopZoomLoop(m_zoomInButtonTimer);
    }

    @UiHandler("zoomInButton")
    public void onZoomInButtonMouseOut(MouseOutEvent e) {
        e.preventDefault();
        resetStyleNamesTo(zoomInButton, true, "map-PanZoomControlZoomInButtonMouse");
        stopZoomLoop(m_zoomInButtonTimer);
    }

    @UiHandler("zoomOutButton")
    public void onZoomOutButtonMouseDown(MouseDownEvent e) {
        e.preventDefault();
        resetStyleNamesTo(zoomOutButton, false, "map-PanZoomControlZoomOutButtonMouse");
        startZoomLoop(m_zoomOutButtonTimer);
    }

    @UiHandler("zoomOutButton")
    public void onZoomOutButtonMouseUp(MouseUpEvent e) {
        e.preventDefault();
        resetStyleNamesTo(zoomOutButton, false, "map-PanZoomControlZoomOutButtonMouseOver");
        stopZoomLoop(m_zoomOutButtonTimer);
    }

    @UiHandler("zoomOutButton")
    public void onZoomOutButtonMouseOut(MouseOutEvent e) {
        e.preventDefault();
        resetStyleNamesTo(zoomOutButton, false, "map-PanZoomControlZoomOutButtonMouse");
        stopZoomLoop(m_zoomOutButtonTimer);
    }

    @UiHandler("zoomOutButton")
    public void onZoomOutButtonMouseOver(MouseOverEvent e) {
        e.preventDefault();
        resetStyleNamesTo(zoomOutButton, false, "map-PanZoomControlZoomOutButtonMouseOver");
        stopZoomLoop(m_zoomOutButtonTimer);
    }

    /**
     * Catch-all method for making sure only one button type is set on the element at any time.
     * This is the easiest necessary step to take cases such as the user hold-clicking on a button,
     * dragging onto the other button, and releasing their click. 
     * 
     * @param button
     * @param isInButton
     * @param newName 
     */
    private void resetStyleNamesTo(HTML button, boolean isInButton, String newName) {
        if (isInButton) {
            button.removeStyleName("map-PanZoomControlZoomInButtonMouse");
            button.removeStyleName("map-PanZoomControlZoomInButtonMouseOver");
        } else {
            button.removeStyleName("map-PanZoomControlZoomOutButtonMouse");
            button.removeStyleName("map-PanZoomControlZoomOutButtonMouseOver");
        }
        button.addStyleName(newName);
    }
}