diff --git a/src/LegendContent.js b/src/LegendContent.js new file mode 100644 index 0000000..68be45e --- /dev/null +++ b/src/LegendContent.js @@ -0,0 +1,45 @@ +export const LEGEND_HTML = ` +
+
+
+ Raw Location +
+
+ FLP Location +
+
+ FLP = Raw Location +
+
+ +
+ + + + Pickup +
+ +
+ + + + + Actual Pickup +
+ +
+ + + + Dropoff +
+ +
+ + + + + Actual Dropoff +
+
+`; diff --git a/src/LogTable.js b/src/LogTable.js index ba326d3..45a7499 100644 --- a/src/LogTable.js +++ b/src/LogTable.js @@ -170,7 +170,7 @@ function LogTable(props) { }, [props.logData.tripLogs, minTime, maxTime, props.filters]); const columnShortWidth = 50; const columnRegularWidth = 120; - const columnLargeWidth = 150; + const columnLargeWidth = 152; const columns = React.useMemo(() => { const stdColumns = _.filter( [ diff --git a/src/Map.js b/src/Map.js index a8148cf..bc49a5e 100644 --- a/src/Map.js +++ b/src/Map.js @@ -9,6 +9,7 @@ import { decode } from "s2polyline-ts"; import TrafficPolyline from "./TrafficPolyline"; import { TripObjects } from "./TripObjects"; import { getToggleHandlers } from "./MapToggles.js"; +import { LEGEND_HTML } from "./LegendContent.js"; function MapComponent({ logData, @@ -109,6 +110,7 @@ function MapComponent({ element: mapDivRef.current, locationProviders: [locationProviderRef.current], mapOptions: { mapId, mapTypeControl: true, streetViewControl: true, maxZoom: 22 }, + automaticViewportMode: "NONE", }); const map = jsMapView.map; mapRef.current = map; @@ -213,6 +215,36 @@ function MapComponent({ bottomControlsWrapper.appendChild(toggleContainer); map.controls[window.google.maps.ControlPosition.LEFT_BOTTOM].push(bottomControlsWrapper); + // Legend Controls + const legendToggleContainer = document.createElement("div"); + legendToggleContainer.className = "map-toggle-container"; + legendToggleContainer.style.marginTop = "10px"; + legendToggleContainer.style.marginRight = "10px"; + legendToggleContainer.style.marginBottom = "0px"; + + const legendBtn = document.createElement("button"); + legendBtn.textContent = "Legend"; + legendBtn.className = "map-toggle-button"; + legendToggleContainer.appendChild(legendBtn); + + const legendContentDiv = document.createElement("div"); + legendContentDiv.style.display = "none"; + legendContentDiv.innerHTML = LEGEND_HTML; + + legendBtn.onclick = () => { + const isHidden = legendContentDiv.style.display === "none"; + if (isHidden) { + legendContentDiv.style.display = "block"; + legendBtn.classList.add("active"); + } else { + legendContentDiv.style.display = "none"; + legendBtn.classList.remove("active"); + } + }; + + map.controls[window.google.maps.ControlPosition.TOP_RIGHT].push(legendToggleContainer); + map.controls[window.google.maps.ControlPosition.TOP_RIGHT].push(legendContentDiv); + const centerListener = map.addListener( "center_changed", _.debounce(() => { @@ -441,30 +473,73 @@ function MapComponent({ } const rawLocation = _.get(locationObj, "rawlocation"); - if (rawLocation?.latitude && rawLocation?.longitude) { - const rawPos = { lat: rawLocation.latitude, lng: rawLocation.longitude }; - if (vehicleMarkersRef.current.rawLocation) { - vehicleMarkersRef.current.rawLocation.setPosition(rawPos); - if (!vehicleMarkersRef.current.rawLocation.getMap()) { - vehicleMarkersRef.current.rawLocation.setMap(map); + const flpLocation = _.get(locationObj, "flplocation"); + + const rawLat = rawLocation?.latitude; + const rawLng = rawLocation?.longitude; + const flpLat = flpLocation?.latitude; + const flpLng = flpLocation?.longitude; + + const hasRaw = rawLat !== undefined && rawLng !== undefined; + const hasFlp = flpLat !== undefined && flpLng !== undefined; + const isMatch = hasRaw && hasFlp && rawLat === flpLat && rawLng === flpLng; + + const updateMarker = (markerRefName, position, color, zIndex, scale = 2) => { + if (!position) { + if (vehicleMarkersRef.current[markerRefName]) { + vehicleMarkersRef.current[markerRefName].setMap(null); + } + return; + } + + const pos = { lat: position.latitude, lng: position.longitude }; + if (vehicleMarkersRef.current[markerRefName]) { + vehicleMarkersRef.current[markerRefName].setPosition(pos); + if (!vehicleMarkersRef.current[markerRefName].getMap()) { + vehicleMarkersRef.current[markerRefName].setMap(map); + } + const icon = vehicleMarkersRef.current[markerRefName].getIcon(); + if (icon.fillColor !== color || icon.scale !== scale) { + icon.fillColor = color; + icon.strokeColor = color; + icon.scale = scale; + vehicleMarkersRef.current[markerRefName].setIcon(icon); } } else { - vehicleMarkersRef.current.rawLocation = new window.google.maps.Marker({ - position: rawPos, + vehicleMarkersRef.current[markerRefName] = new window.google.maps.Marker({ + position: pos, map, icon: { path: window.google.maps.SymbolPath.CIRCLE, - fillColor: "#FF0000", + fillColor: color, fillOpacity: 1, - scale: 2, - strokeColor: "#FF0000", + scale: scale, + strokeColor: color, strokeWeight: 1, }, - zIndex: 8, + zIndex: zIndex, }); } - } else if (vehicleMarkersRef.current.rawLocation) { - vehicleMarkersRef.current.rawLocation.setMap(null); + }; + + if (isMatch) { + updateMarker("matchLocation", rawLocation, "#C71585", 8, 3); + updateMarker("rawLocation", null); + updateMarker("flpLocation", null); + } else { + updateMarker("matchLocation", null); + + if (hasRaw) { + updateMarker("rawLocation", rawLocation, "#FF0000", 8, 2); + } else { + updateMarker("rawLocation", null); + } + + if (hasFlp) { + updateMarker("flpLocation", flpLocation, "#4285F4", 8, 2); + } else { + updateMarker("flpLocation", null); + } } if (isFollowingVehicle) {