Package org.onebusaway.webapp.gwt.where_library.view.stops

Source Code of org.onebusaway.webapp.gwt.where_library.view.stops.TransitMapManager

/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onebusaway.webapp.gwt.where_library.view.stops;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.onebusaway.geospatial.model.CoordinateBounds;
import org.onebusaway.geospatial.model.EncodedPolylineBean;
import org.onebusaway.transit_data.model.RouteBean;
import org.onebusaway.transit_data.model.StopBean;
import org.onebusaway.transit_data.model.StopsForRouteBean;
import org.onebusaway.webapp.gwt.common.MapOverlayManager;
import org.onebusaway.webapp.gwt.common.control.Place;
import org.onebusaway.webapp.gwt.common.resources.map.StopIconFactory;
import org.onebusaway.webapp.gwt.common.resources.map.StopIconFactory.ESize;
import org.onebusaway.webapp.gwt.where_library.GeocoderAccuracyToBounds;
import org.onebusaway.webapp.gwt.where_library.impl.StopsForRegionServiceImpl;
import org.onebusaway.webapp.gwt.where_library.view.events.StopClickedEvent;
import org.onebusaway.webapp.gwt.where_library.view.events.StopClickedHandler;

import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.event.MapMoveEndHandler;
import com.google.gwt.maps.client.event.MarkerClickHandler;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.geom.LatLngBounds;
import com.google.gwt.maps.client.overlay.EncodedPolyline;
import com.google.gwt.maps.client.overlay.Icon;
import com.google.gwt.maps.client.overlay.Marker;
import com.google.gwt.maps.client.overlay.MarkerOptions;
import com.google.gwt.maps.client.overlay.Overlay;
import com.google.gwt.maps.client.overlay.Polyline;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class TransitMapManager {

  private StopsForRegionServiceImpl _stopsForRegionService = new StopsForRegionServiceImpl();

  private Map<String, StopAndOverlays> _visibleStopsById = new HashMap<String, StopAndOverlays>();

  private StopsHandler _stopsHandler = new StopsHandler();

  private Set<String> _stopIdsToAlwaysShow = new HashSet<String>();

  private Set<String> _selectedStopIds = new HashSet<String>();

  private List<Overlay> _otherOverlays = new ArrayList<Overlay>();

  private boolean _showStopsInCurrentView = true;

  private MapWidget _map;

  private MapOverlayManager _manager;

  private HandlerManager _handlerManager;

  private RouteBean _selectedRoute = null;

  public TransitMapManager(MapWidget map) {
    _map = map;
    _manager = new MapOverlayManager(_map);

    _map.addMapMoveEndHandler(new MapMoveEndHandlerImpl());
  }

  public HandlerRegistration addStopClickedHandler(StopClickedHandler handler) {
    return ensureHandlers().addHandler(StopClickedEvent.TYPE, handler);
  }

  public MapWidget getMap() {
    return _map;
  }

  public RouteBean getSelectedRoute() {
    return _selectedRoute;
  }

  /****
   * Visualization Modes
   ****/

  public void showStopsInCurrentView() {
    reset(true);
  }

  public void showStopsAtLocation(LatLng point, int zoomLevel) {
    _map.setCenter(point, zoomLevel);
    reset(true);
  }

  public void showStops(List<StopBean> stops) {
    reset(false, stops);
  }

  public void showStopsForRoute(RouteBean route,
      StopsForRouteBean stopsForRoute, boolean centerViewOnRoute) {

    reset(false, stopsForRoute.getStops());
    _selectedRoute = route;

    for (EncodedPolylineBean path : stopsForRoute.getPolylines()) {

      EncodedPolyline epl = EncodedPolyline.newInstance(path.getPoints(), 32,
          path.getLevels(3), 4);
      epl.setColor("#4F64BA");
      epl.setWeight(3);
      epl.setOpacity(1.0);
      Polyline polyline = Polyline.fromEncoded(epl);
      _manager.addOverlay(polyline);
      _otherOverlays.add(polyline);
    }

    if (centerViewOnRoute) {
      System.out.println("center on route");
      // Center the map on the bounds of the route
      LatLngBounds bounds = LatLngBounds.newInstance();
      for (StopBean stop : stopsForRoute.getStops())
        bounds.extend(LatLng.newInstance(stop.getLat(), stop.getLon()));

      if (!bounds.isEmpty()) {
        int zoomLevel = _map.getBoundsZoomLevel(bounds);
        _map.setCenter(bounds.getCenter(), zoomLevel);
      }
    }
  }

  public void showStop(StopBean stop, boolean showStopsInCurrentView) {
    LatLng point = LatLng.newInstance(stop.getLat(), stop.getLon());
    _map.setCenter(point, 17);
    Set<String> selectedStopIds = new HashSet<String>();
    selectedStopIds.add(stop.getId());
    reset(showStopsInCurrentView, Arrays.asList(stop), selectedStopIds);
  }

  public void showPlace(Place place, boolean showStopsInCurrentView,
      PlaceClickHandler clickHandler) {
    System.out.println("accuracy=" + place.getAccuracy());
    int zoomLevel = GeocoderAccuracyToBounds.getZoomLevelForAccuracy(place.getAccuracy());
    _map.setCenter(place.getLocation(), zoomLevel);
    reset(true);
    addPlaceToMap(place, clickHandler);
  }

  public void showPlaces(List<Place> places, boolean showStopsInCurrentView,
      PlaceClickHandler clickHandler) {

    LatLngBounds bounds = LatLngBounds.newInstance();
    for (Place place : places)
      bounds.extend(place.getLocation());
    if (!bounds.isEmpty())
      _map.setCenter(bounds.getCenter(), _map.getBoundsZoomLevel(bounds));

    reset(showStopsInCurrentView);
    for (Place place : places)
      addPlaceToMap(place, clickHandler);
  }

  /****
   * Private Methods
   ****/

  private HandlerManager ensureHandlers() {
    return _handlerManager == null ? _handlerManager = new HandlerManager(this)
        : _handlerManager;
  }

  private void reset(boolean showStopsInCurrentView) {
    reset(showStopsInCurrentView, new ArrayList<StopBean>());
  }

  private void reset(boolean showStopsInCurrentView,
      List<StopBean> stopsToAlwaysShow) {
    reset(showStopsInCurrentView, stopsToAlwaysShow, new HashSet<String>());
  }

  private void reset(boolean showStopsInCurrentView,
      List<StopBean> stopsToAlwaysShow, Set<String> selectedStopIds) {

    _showStopsInCurrentView = showStopsInCurrentView;

    _stopIdsToAlwaysShow.clear();
    for (StopBean stop : stopsToAlwaysShow)
      _stopIdsToAlwaysShow.add(stop.getId());

    for (Overlay overlay : _otherOverlays)
      _manager.removeOverlay(overlay);
    _otherOverlays.clear();

    for (StopAndOverlays stopAndOverlay : _visibleStopsById.values()) {
      List<Overlay> overlays = stopAndOverlay.getOverlays();
      for (Overlay overlay : overlays)
        _manager.removeOverlay(overlay);
    }

    _visibleStopsById.clear();
    _selectedStopIds.clear();
    _selectedStopIds.addAll(selectedStopIds);

    _stopsHandler.onSuccess(stopsToAlwaysShow);

    _selectedRoute = null;

    refresh();
  }

  private void refresh() {

    if (_showStopsInCurrentView) {

      int zoom = _map.getZoomLevel();

      if (zoom < 17) {
        return;
      }

      final CoordinateBounds bounds = computeBounds();

      for (Iterator<Map.Entry<String, StopAndOverlays>> it = _visibleStopsById.entrySet().iterator(); it.hasNext();) {
        Entry<String, StopAndOverlays> entry = it.next();
        StopAndOverlays stopAndOverlays = entry.getValue();
        StopBean stop = stopAndOverlays.getStop();
        if (!bounds.contains(stop.getLat(), stop.getLon())) {
          it.remove();
          for (Overlay overlay : stopAndOverlays.getOverlays())
            _manager.removeOverlay(overlay);
        }
      }

      // Update the map
      DeferredCommand.addCommand(new Command() {
        @Override
        public void execute() {
          _stopsForRegionService.getStopsForRegion(bounds, _stopsHandler);
        }
      });

    } else {

      for (StopAndOverlays stopAndOverlays : _visibleStopsById.values()) {
        StopBean stop = stopAndOverlays.getStop();
        if (_stopIdsToAlwaysShow.contains(stop.getId()))
          continue;
        for (Overlay overlay : stopAndOverlays.getOverlays())
          _manager.removeOverlay(overlay);
      }
      _visibleStopsById.keySet().retainAll(_stopIdsToAlwaysShow);
    }
  }

  private CoordinateBounds computeBounds() {
    LatLngBounds r = _map.getBounds();
    LatLng ne = r.getNorthEast();
    LatLng sw = r.getSouthWest();

    double latMin = sw.getLatitude();
    double lonMin = sw.getLongitude();
    double latMax = ne.getLatitude();
    double lonMax = ne.getLongitude();

    return new CoordinateBounds(latMin, lonMin, latMax, lonMax);
  }

  private MarkerClickHandler getClickHandlerForStop(final StopBean stop) {
    MarkerClickHandler clickHandler = new MarkerClickHandler() {
      public void onClick(MarkerClickEvent event) {
        ensureHandlers().fireEvent(new StopClickedEvent(stop));
      }
    };
    return clickHandler;
  }

  private Marker getStopMarker(final StopBean stop, final LatLng p, ESize size) {

    MarkerOptions opts = MarkerOptions.newInstance();
    boolean isSelected = false;

    Icon icon = StopIconFactory.getStopIcon(stop, size, isSelected);
    opts.setIcon(icon);
    return new Marker(p, opts);
  }

  private void addOverlayAtZoom(Overlay overlay, int from, int to) {
    _manager.addOverlay(overlay, from, to);
  }

  private void addPlaceToMap(final Place place,
      final PlaceClickHandler clickHandler) {
    LatLng point = place.getLocation();
    Marker marker = new Marker(point);

    if (clickHandler != null) {
      marker.addMarkerClickHandler(new MarkerClickHandler() {
        @Override
        public void onClick(MarkerClickEvent event) {
          clickHandler.onPlaceClicked(place);
        }
      });
    }
    _manager.addOverlay(marker);
    _otherOverlays.add(marker);
  }

  /****
   * Internal Classes
   ****/

  private class MapMoveEndHandlerImpl implements MapMoveEndHandler {
    @Override
    public void onMoveEnd(MapMoveEndEvent event) {
      refresh();
    }
  }

  private class StopsHandler implements AsyncCallback<List<StopBean>> {

    public void onSuccess(List<StopBean> stops) {

      for (StopBean stop : stops) {

        if (_visibleStopsById.containsKey(stop.getId()))
          continue;

        StopAndOverlays stopAndOverlays = new StopAndOverlays(stop);
        _visibleStopsById.put(stop.getId(), stopAndOverlays);

        LatLng p = LatLng.newInstance(stop.getLat(), stop.getLon());

        MarkerClickHandler clickHandler = getClickHandlerForStop(stop);

        // Show some close up stops by default
        Marker largerMarker = getStopMarker(stop, p, ESize.LARGE);

        largerMarker.addMarkerClickHandler(clickHandler);

        addOverlayAtZoom(largerMarker, 17, 20);

        stopAndOverlays.addOverlays(largerMarker);

        // If we're not showing stops in our current view, it must mean we're in
        // route view, so we show the stops more zoomed out
        if (!_showStopsInCurrentView) {

          Marker mediumMarker = getStopMarker(stop, p, ESize.MEDIUM);
          mediumMarker.addMarkerClickHandler(clickHandler);
          addOverlayAtZoom(mediumMarker, 16, 17);

          Marker smallMarker = getStopMarker(stop, p, ESize.SMALL);
          smallMarker.addMarkerClickHandler(clickHandler);
          addOverlayAtZoom(smallMarker, 13, 16);

          Marker tinyMarker = getStopMarker(stop, p, ESize.TINY);
          tinyMarker.addMarkerClickHandler(clickHandler);
          addOverlayAtZoom(tinyMarker, 9, 13);

          stopAndOverlays.addOverlays(mediumMarker, smallMarker, tinyMarker);
        }

        if (_selectedStopIds.contains(stop.getId())) {
          Marker big = StopIconFactory.getStopSelectionCircle(p, true);
          Marker small = StopIconFactory.getStopSelectionCircle(p, false);
          addOverlayAtZoom(small, 16, 17);
          addOverlayAtZoom(big, 17, 20);
          stopAndOverlays.addOverlays(big, small);
        }
      }
    }

    @Override
    public void onFailure(Throwable arg0) {
      arg0.printStackTrace();
    }
  }

  private class StopAndOverlays {

    private StopBean _stop;

    private List<Overlay> _overlays = new ArrayList<Overlay>();

    public StopAndOverlays(StopBean stop) {
      _stop = stop;
    }

    public StopBean getStop() {
      return _stop;
    }

    public List<Overlay> getOverlays() {
      return _overlays;
    }

    public void addOverlays(Overlay... overlays) {
      for (Overlay overlay : overlays)
        _overlays.add(overlay);
    }
  }

}
TOP

Related Classes of org.onebusaway.webapp.gwt.where_library.view.stops.TransitMapManager

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.