diff options
-rw-r--r-- | src/org/traccar/web/client/Application.java | 16 | ||||
-rw-r--r-- | src/org/traccar/web/client/controller/MapController.java | 26 | ||||
-rw-r--r-- | src/org/traccar/web/client/view/ArchiveView.java | 21 | ||||
-rw-r--r-- | src/org/traccar/web/client/view/MapPositionRenderer.java | 114 | ||||
-rw-r--r-- | src/org/traccar/web/client/view/MapView.java | 125 | ||||
-rw-r--r-- | src/org/traccar/web/client/view/MarkerIconFactory.java | 32 | ||||
-rw-r--r-- | src/org/traccar/web/server/model/DataServiceImpl.java | 3 |
7 files changed, 258 insertions, 79 deletions
diff --git a/src/org/traccar/web/client/Application.java b/src/org/traccar/web/client/Application.java index 22f20d8c..046dd734 100644 --- a/src/org/traccar/web/client/Application.java +++ b/src/org/traccar/web/client/Application.java @@ -5,6 +5,7 @@ import java.util.List; import org.traccar.web.client.controller.ArchiveController; import org.traccar.web.client.controller.DeviceController; import org.traccar.web.client.controller.MapController; +import org.traccar.web.client.model.BaseStoreHandlers; import org.traccar.web.client.model.DataService; import org.traccar.web.client.model.DataServiceAsync; import org.traccar.web.client.view.ApplicationView; @@ -13,6 +14,7 @@ import org.traccar.web.shared.model.Position; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.ui.RootPanel; +import com.sencha.gxt.data.shared.event.StoreHandlers; public class Application { @@ -32,6 +34,7 @@ public class Application { deviceController = new DeviceController(deviceHandler); mapController = new MapController(); archiveController = new ArchiveController(archiveHanlder, deviceController.getDeviceStore()); + archiveController.getPositionStore().addStoreHandlers(archiveStoreHandler); view = new ApplicationView( deviceController.getView(), mapController.getView(), archiveController.getView()); @@ -53,7 +56,7 @@ public class Application { @Override public void onSelected(Device device) { - mapController.select(device); + mapController.selectDevice(device); } @Override @@ -76,7 +79,16 @@ public class Application { @Override public void onSelected(Position position) { - // TODO select something on map? + mapController.selectArchivePosition(position); + } + + }; + + private StoreHandlers<Position> archiveStoreHandler = new BaseStoreHandlers<Position>() { + + @Override + public void onAnything() { + mapController.showArchivePositions(archiveController.getPositionStore().getAll()); } }; diff --git a/src/org/traccar/web/client/controller/MapController.java b/src/org/traccar/web/client/controller/MapController.java index 5ab5bbcf..738b2811 100644 --- a/src/org/traccar/web/client/controller/MapController.java +++ b/src/org/traccar/web/client/controller/MapController.java @@ -1,5 +1,8 @@ package org.traccar.web.client.controller; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; import java.util.List; import org.traccar.web.client.Application; @@ -13,7 +16,7 @@ import com.sencha.gxt.widget.core.client.ContentPanel; public class MapController implements ContentController { - private static final int UPDATE_INTERVAL = 10000; + private static final int UPDATE_INTERVAL = 15000; private MapView mapView; @@ -44,7 +47,7 @@ public class MapController implements ContentController { Application.getDataService().getLatestPositions(new AsyncCallback<List<Position>>() { @Override public void onSuccess(List<Position> result) { - mapView.showPositions(result); + mapView.showLatestPositions(result); updateTimer.schedule(UPDATE_INTERVAL); } @Override @@ -54,8 +57,23 @@ public class MapController implements ContentController { }); } - public void select(Device device) { - mapView.select(device, true); + public void selectDevice(Device device) { + mapView.selectDevice(device); + } + + public void showArchivePositions(List<Position> positions) { + List<Position> sortedPositions = new LinkedList<Position>(positions); + Collections.sort(sortedPositions, new Comparator<Position>() { + @Override + public int compare(Position o1, Position o2) { + return o1.getTime().compareTo(o2.getTime()); + } + }); + mapView.showArchivePositions(sortedPositions); + } + + public void selectArchivePosition(Position position) { + mapView.selectArchivePosition(position); } } diff --git a/src/org/traccar/web/client/view/ArchiveView.java b/src/org/traccar/web/client/view/ArchiveView.java index f61ffccc..5d74f37c 100644 --- a/src/org/traccar/web/client/view/ArchiveView.java +++ b/src/org/traccar/web/client/view/ArchiveView.java @@ -28,8 +28,9 @@ import com.sencha.gxt.widget.core.client.form.TimeField; import com.sencha.gxt.widget.core.client.grid.ColumnConfig; import com.sencha.gxt.widget.core.client.grid.ColumnModel; import com.sencha.gxt.widget.core.client.grid.Grid; +import com.sencha.gxt.widget.core.client.selection.SelectionChangedEvent; -public class ArchiveView { +public class ArchiveView implements SelectionChangedEvent.SelectionChangedHandler<Position> { private static ArchiveViewUiBinder uiBinder = GWT.create(ArchiveViewUiBinder.class); @@ -107,6 +108,7 @@ public class ArchiveView { uiBinder.createAndBindUi(this); + grid.getSelectionModel().addSelectionChangedHandler(this); grid.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); // Initialize with current time @@ -117,6 +119,15 @@ public class ArchiveView { toTime.setValue(now); } + @Override + public void onSelectionChanged(SelectionChangedEvent<Position> event) { + if (event.getSelection().isEmpty()) { + archiveHandler.onSelected(null); + } else { + archiveHandler.onSelected(event.getSelection().get(0)); + } + } + @SuppressWarnings("deprecation") private static Date getCombineDate(DateField dateField, TimeField timeField) { Date result = null; @@ -147,7 +158,13 @@ public class ArchiveView { @Override public void onAnything() { - deviceCombo.setValue(deviceStore.findModel(deviceCombo.getValue())); + Device oldDevice = deviceCombo.getValue(); + if (oldDevice != null) { + Device newDevice = deviceStore.findModel(oldDevice); + if (newDevice != null) { + deviceCombo.setValue(newDevice); + } + } } }; diff --git a/src/org/traccar/web/client/view/MapPositionRenderer.java b/src/org/traccar/web/client/view/MapPositionRenderer.java new file mode 100644 index 00000000..5a756c78 --- /dev/null +++ b/src/org/traccar/web/client/view/MapPositionRenderer.java @@ -0,0 +1,114 @@ +package org.traccar.web.client.view; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.gwtopenmaps.openlayers.client.Icon; +import org.gwtopenmaps.openlayers.client.Marker; +import org.gwtopenmaps.openlayers.client.feature.VectorFeature; +import org.gwtopenmaps.openlayers.client.geometry.LineString; +import org.gwtopenmaps.openlayers.client.geometry.Point; +import org.gwtopenmaps.openlayers.client.layer.Markers; +import org.gwtopenmaps.openlayers.client.layer.Vector; +import org.traccar.web.shared.model.Device; +import org.traccar.web.shared.model.Position; + + +public class MapPositionRenderer { + + private final MapView mapView; + private final Vector vectorLayer; + private final Markers markerLayer; + private final MarkerIconFactory.IconType iconType; + + public MapPositionRenderer(MapView mapView, MarkerIconFactory.IconType iconType) { + this.mapView = mapView; + vectorLayer = mapView.getVectorLayer(); + markerLayer = mapView.getMarkerLayer(); + this.iconType = iconType; + } + + /* + * TODO: a lot of mess here + * 1. changeMarkerIcon doesn't save new marker + * 2. if device selected save device instead of position + * 3. find way to change marker icon + * 4. shorter cleaner methods + * ... maybe something else + */ + + private void changeMarkerIcon(Marker marker, Icon icon) { + Marker newMarker = new Marker(marker.getLonLat(), icon); + markerLayer.removeMarker(marker); + markerLayer.addMarker(newMarker); + } + + private Map<Long, Marker> markerMap = new HashMap<Long, Marker>(); // Position.id -> Marker + private Map<Long, Long> deviceMap = new HashMap<Long, Long>(); // Device.id -> Position.id + + private Long selectedPositionId; + + public void showPositions(List<Position> positions) { + for (Marker marker : markerMap.values()) { + markerLayer.removeMarker(marker); + } + markerMap.clear(); + deviceMap.clear(); + + for (Position position : positions) { + Marker marker = new Marker( + mapView.createLonLat(position.getLongitude(), position.getLatitude()), + MarkerIconFactory.getIcon(iconType, false)); + markerMap.put(position.getId(), marker); + deviceMap.put(position.getDevice().getId(), position.getId()); + markerLayer.addMarker(marker); + } + + if (selectedPositionId != null) { + selectPosition(null, selectedPositionId, false); + } + } + + public void showTrack(List<Position> positions) { + vectorLayer.destroyFeatures(); + + if (!positions.isEmpty()) { + Point[] linePoints = new Point[positions.size()]; + + int i = 0; + for (Position position : positions) { + linePoints[i++] = mapView.createPoint(position.getLongitude(), position.getLatitude()); + } + + LineString lineString = new LineString(linePoints); + vectorLayer.addFeature(new VectorFeature(lineString)); + //mapView.getMap().zoomToExtent(lineString.getBounds()); + } + } + + public void selectPosition(Position position, boolean center) { + selectPosition(selectedPositionId, position.getId(), center); + } + + public void selectDevice(Device device, boolean center) { + Long positionId = (device != null) ? deviceMap.get(device.getId()) : null; + selectPosition(selectedPositionId, positionId, center); + } + + private void selectPosition(Long oldPositionId, Long newPositionId, boolean center) { + if (oldPositionId != null && markerMap.containsKey(oldPositionId)) { + changeMarkerIcon(markerMap.get(oldPositionId), MarkerIconFactory.getIcon(iconType, false)); + selectedPositionId = null; + } + if (newPositionId != null && markerMap.containsKey(newPositionId)) { + Marker marker = markerMap.get(newPositionId); + changeMarkerIcon(marker, MarkerIconFactory.getIcon(iconType, true)); + if (center) { + mapView.getMap().panTo(marker.getLonLat()); + } + selectedPositionId = newPositionId; + } + } + +} diff --git a/src/org/traccar/web/client/view/MapView.java b/src/org/traccar/web/client/view/MapView.java index af38c443..a7d1dad2 100644 --- a/src/org/traccar/web/client/view/MapView.java +++ b/src/org/traccar/web/client/view/MapView.java @@ -1,21 +1,19 @@ package org.traccar.web.client.view; -import java.util.AbstractMap; -import java.util.HashMap; import java.util.List; -import org.gwtopenmaps.openlayers.client.Icon; import org.gwtopenmaps.openlayers.client.LonLat; import org.gwtopenmaps.openlayers.client.Map; import org.gwtopenmaps.openlayers.client.MapOptions; import org.gwtopenmaps.openlayers.client.MapWidget; -import org.gwtopenmaps.openlayers.client.Marker; -import org.gwtopenmaps.openlayers.client.Pixel; import org.gwtopenmaps.openlayers.client.Projection; -import org.gwtopenmaps.openlayers.client.Size; import org.gwtopenmaps.openlayers.client.control.ScaleLine; +import org.gwtopenmaps.openlayers.client.geometry.Point; import org.gwtopenmaps.openlayers.client.layer.Markers; +import org.gwtopenmaps.openlayers.client.layer.MarkersOptions; import org.gwtopenmaps.openlayers.client.layer.OSM; +import org.gwtopenmaps.openlayers.client.layer.Vector; +import org.gwtopenmaps.openlayers.client.layer.VectorOptions; import org.traccar.web.shared.model.Device; import org.traccar.web.shared.model.Position; @@ -25,34 +23,7 @@ import com.google.gwt.event.logical.shared.ResizeHandler; import com.google.gwt.user.client.Command; import com.sencha.gxt.widget.core.client.ContentPanel; -class MarkerIconFactory { - private static final Size iconSize = new Size(21, 25); - private static final Pixel iconOffset = new Pixel(-10.5f, -25.0f); - - private static final String iconUrl = "http://www.openlayers.org/api/img/"; - private static final String iconRed = iconUrl + "marker.png"; - private static final String iconBlue = iconUrl + "marker-blue.png"; - private static final String iconGreen = iconUrl + "marker-green.png"; - private static final String iconGold = iconUrl + "marker-gold.png"; - - public static Icon getLocationIcon() { - return new Icon(iconRed, iconSize, iconOffset); - } - - public static Icon getSelectedLocationIcon() { - return new Icon(iconGreen, iconSize, iconOffset); - } - - public static Icon getArchiveIcon() { - return new Icon(iconBlue, iconSize, iconOffset); - } - - public static Icon getSelectedArchiveIcon() { - return new Icon(iconGold, iconSize, iconOffset); - } - -} public class MapView { @@ -64,11 +35,30 @@ public class MapView { private MapWidget mapWidget; private Map map; + private Vector vectorLayer; private Markers markerLayer; - private LonLat createPoint(double longitude, double latitude) { - LonLat point = new LonLat(longitude, latitude); - point.transform(new Projection("EPSG:4326").getProjectionCode(), map.getProjection()); + public Map getMap() { + return map; + } + + public Vector getVectorLayer() { + return vectorLayer; + } + + public Markers getMarkerLayer() { + return markerLayer; + } + + public LonLat createLonLat(double longitude, double latitude) { + LonLat lonLat = new LonLat(longitude, latitude); + lonLat.transform(new Projection("EPSG:4326").getProjectionCode(), map.getProjection()); + return lonLat; + } + + public Point createPoint(double x, double y) { + Point point = new Point(x, y); + point.transform(new Projection("EPSG:4326"), new Projection(map.getProjection())); return point; } @@ -78,6 +68,8 @@ public class MapView { MapOptions defaultMapOptions = new MapOptions(); defaultMapOptions.setNumZoomLevels(16); + defaultMapOptions.setProjection("EPSG:4326"); + defaultMapOptions.setDisplayProjection(new Projection("EPSG:4326")); mapWidget = new MapWidget("100%", "100%", defaultMapOptions); map = mapWidget.getMap(); @@ -85,12 +77,19 @@ public class MapView { OSM mapLayer = OSM.Mapnik("Mapnik"); mapLayer.setIsBaseLayer(true); - markerLayer = new Markers("Markers"); + VectorOptions vectorOptions = new VectorOptions(); + vectorOptions.setProjection("EPSG:4326"); + vectorLayer = new Vector("Vector", vectorOptions); + + MarkersOptions markersOptions = new MarkersOptions(); + markersOptions.setProjection("EPSG:4326"); + markerLayer = new Markers("Markers", markersOptions); map.addLayer(mapLayer); + map.addLayer(vectorLayer); map.addLayer(markerLayer); map.addControl(new ScaleLine()); - map.setCenter(createPoint(30, 60), 1); + map.setCenter(createLonLat(12.5, 41.9), 1); contentPanel.add(mapWidget); @@ -106,44 +105,30 @@ public class MapView { }); } }); + + latestPositionRenderer = new MapPositionRenderer(this, MarkerIconFactory.IconType.iconLatest); + archivePositionRenderer = new MapPositionRenderer(this, MarkerIconFactory.IconType.iconArchive); + } + + private final MapPositionRenderer latestPositionRenderer; + + private final MapPositionRenderer archivePositionRenderer; + + public void showLatestPositions(List<Position> positions) { + latestPositionRenderer.showPositions(positions); } - private AbstractMap<Long, Marker> markerMap = new HashMap<Long, Marker>(); - private Device selectedDevice; - - public void showPositions(List<Position> positions) { - markerMap.clear(); - markerLayer.clearMarkers(); - for (Position position : positions) { - Marker marker = new Marker( - createPoint(position.getLongitude(), position.getLatitude()), MarkerIconFactory.getLocationIcon()); - markerMap.put(position.getDevice().getId(), marker); - markerLayer.addMarker(marker); - } - if (selectedDevice != null) { - select(selectedDevice, false); - } + public void showArchivePositions(List<Position> positions) { + archivePositionRenderer.showTrack(positions); + archivePositionRenderer.showPositions(positions); } - private void changeMarkerIcon(Marker marker, Icon icon) { - Marker newMarker = new Marker(marker.getLonLat(), icon); - markerLayer.removeMarker(marker); - markerLayer.addMarker(newMarker); + public void selectDevice(Device device) { + latestPositionRenderer.selectDevice(device, true); } - public void select(Device device, boolean center) { - if (selectedDevice != null) { - changeMarkerIcon(markerMap.get(selectedDevice.getId()), MarkerIconFactory.getLocationIcon()); - selectedDevice = null; - } - if (device != null && markerMap.containsKey(device.getId())) { - Marker marker = markerMap.get(device.getId()); - if (center) { - map.panTo(marker.getLonLat()); - } - changeMarkerIcon(marker, MarkerIconFactory.getSelectedLocationIcon()); - selectedDevice = device; - } + public void selectArchivePosition(Position position) { + archivePositionRenderer.selectPosition(position, true); } } diff --git a/src/org/traccar/web/client/view/MarkerIconFactory.java b/src/org/traccar/web/client/view/MarkerIconFactory.java new file mode 100644 index 00000000..484a6a40 --- /dev/null +++ b/src/org/traccar/web/client/view/MarkerIconFactory.java @@ -0,0 +1,32 @@ +package org.traccar.web.client.view; + +import org.gwtopenmaps.openlayers.client.Icon; +import org.gwtopenmaps.openlayers.client.Pixel; +import org.gwtopenmaps.openlayers.client.Size; + +class MarkerIconFactory { + + private static final Size iconSize = new Size(21, 25); + private static final Pixel iconOffset = new Pixel(-10.5f, -25.0f); + + private static final String iconUrl = "http://www.openlayers.org/api/img/"; + private static final String iconRed = iconUrl + "marker.png"; + private static final String iconBlue = iconUrl + "marker-blue.png"; + private static final String iconGreen = iconUrl + "marker-green.png"; + private static final String iconGold = iconUrl + "marker-gold.png"; + + public static enum IconType { + iconLatest, + iconArchive + }; + + public static Icon getIcon(IconType type, boolean selected) { + if (type == IconType.iconLatest) { + return new Icon(selected ? iconGreen : iconRed, iconSize, iconOffset); + } else if (type == IconType.iconArchive) { + return new Icon(selected ? iconGold : iconBlue, iconSize, iconOffset); + } + return null; + } + +} diff --git a/src/org/traccar/web/server/model/DataServiceImpl.java b/src/org/traccar/web/server/model/DataServiceImpl.java index f9d0e7e3..9c69b48e 100644 --- a/src/org/traccar/web/server/model/DataServiceImpl.java +++ b/src/org/traccar/web/server/model/DataServiceImpl.java @@ -142,7 +142,8 @@ public class DataServiceImpl extends RemoteServiceServlet implements DataService try { device = entityManager.merge(device); user.getDevices().remove(device); - entityManager.remove(device); + // If you want to remove device you need to remove all linked positions + //entityManager.remove(device); entityManager.getTransaction().commit(); } catch (Exception e) { entityManager.getTransaction().rollback(); |