Skip to content

Commit

Permalink
Merge pull request #164 from Type-Style/dev
Browse files Browse the repository at this point in the history
Release 1.1_2
  • Loading branch information
Type-Style committed Sep 15, 2024
2 parents 4e099e2 + eafd88e commit afb727e
Show file tree
Hide file tree
Showing 13 changed files with 161 additions and 57 deletions.
18 changes: 14 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"@mui/icons-material": "^5.16.7",
"@mui/material": "^5.16.7",
"@types/leaflet-rotatedmarker": "^0.2.5",
"axios": "^1.7.4",
"axios": "^1.7.5",
"bcrypt": "^5.1.1",
"chalk": "^4.1.2",
"compression": "^1.7.4",
Expand All @@ -87,6 +87,7 @@
"jsonwebtoken": "^9.0.2",
"leaflet": "^1.9.4",
"leaflet-defaulticon-compatibility": "^0.1.2",
"leaflet-easybutton": "^2.4.0",
"leaflet-rotatedmarker": "^0.2.0",
"module-alias": "^2.2.3",
"react": "^18.3.1",
Expand Down
4 changes: 3 additions & 1 deletion src/client/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,7 @@
},
"rules": {
//"react/jsx-key": false
}
},
"ignorePatterns": ["types_easyButton.d.ts" ]

}
41 changes: 41 additions & 0 deletions src/client/components/LocationButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { useEffect } from 'react'
import { useMap } from "react-leaflet";
import L from 'leaflet';
import GpsFixedIcon from '@mui/icons-material/GpsFixed';
import { renderToString } from 'react-dom/server';

// Used to recenter the map to new coordinates
export const LocationButton = ({ lat, lon }: { lat: number, lon: number }) => {
const map = useMap();
const gpsIcon = renderToString(<GpsFixedIcon style={{ width: '100%', height: '100%', fill: "currentcolor" }} />);
let justClicked = false;
useEffect(() => {
L.easyButton(gpsIcon, function (btn, map) {
justClicked = true;
map.locate({
enableHighAccuracy: true,
watch: true,
}).on("locationfound", function (e) {

btn.button.classList.add("active");
const bounds = L.latLngBounds([[lat, lon], e.latlng]);
if (justClicked) {
map.fitBounds(bounds);
}

//map.flyTo(e.latlng, map.getZoom());

L.marker(e.latlng, {
icon: L.divIcon({
className: "customMarkerIcon geoLocation end none",
iconSize: L.point(17, 17),
popupAnchor: [0, -15],
}),
}).bindPopup("Your are here :)").addTo(map);

justClicked = false;
});
}).addTo(map);
}, [map]);
return null;
};
88 changes: 50 additions & 38 deletions src/client/components/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { Context } from "../components/App";
import { LayersControl, MapContainer, Marker, Polyline, Popup, TileLayer, useMapEvents } from 'react-leaflet'
import { toGamut, parse, Oklch, formatCss } from 'culori';
import L from 'leaflet';
import "leaflet-easybutton/src/easy-button.js";
import "leaflet-easybutton/src/easy-button.css";
import 'leaflet-rotatedmarker';
import 'leaflet/dist/leaflet.css';
import "../css/map.css";
Expand All @@ -11,6 +13,7 @@ import { layers } from "../scripts/layers";
import MarkerClusterGroup from "@changey/react-leaflet-markercluster";
import "@changey/react-leaflet-markercluster/dist/styles.min.css";
import { MapRecenter } from "./MapCenter";
import { LocationButton } from "./LocationButton";

const MultiColorPolyline = ({ cleanEntries }: { cleanEntries: Models.IEntry[] }) => {
const [useRelativeColors] = useState<boolean>(true); // Change candidate; Use color in range to maximum speed, like from 0 to max, rather than fixed range
Expand All @@ -29,7 +32,8 @@ const MultiColorPolyline = ({ cleanEntries }: { cleanEntries: Models.IEntry[] })
}

return cleanEntries.map((entry, index) => {
if (!index) { return false; }
if (!index || entry.time.diff > 300) { return false; }

const previousEntry = cleanEntries[index - 1];
const color = startColor;
const currentSpeed = entry.speed.gps * 3.6; // convert to km/h
Expand All @@ -49,7 +53,6 @@ const MultiColorPolyline = ({ cleanEntries }: { cleanEntries: Models.IEntry[] })
weight={5}
dashArray={strokeDashArray}
lineCap={"butt"}

/>)
});
}
Expand All @@ -59,18 +62,14 @@ function Map({ entries }: { entries: Models.IEntry[] }) {
if (!entries?.length) {
return <span className="noData cut">No Data to be displayed</span>
}

const [, , , , mode, , , mapToken] = useContext(Context);
const [mapStyle, setMapStyle] = useState(mode);

const lastEntry = entries.at(-1);
const cleanEntries = entries.filter((entry) => !entry.ignore);
const cleanEntriesWithoutLast = cleanEntries.slice(0, -1);

const replaceKeyword = "XXXREPLACEXXX";

// Function to create custom icon with dynamic className
function createCustomIcon(entry: Models.IEntry) {
function getClassName(entry: Models.IEntry) {
let className = "none";
let iconSize = 14;
if (entry.index == 0 || entry.time.diff >= 300) {
Expand All @@ -84,6 +83,15 @@ function Map({ entries }: { entries: Models.IEntry[] }) {
iconSize = 22;
}

return {
className,
iconSize
}
}


// Function to create custom icon with dynamic className
function createCustomIcon(entry: Models.IEntry, iconObj: { className: string, iconSize: number }) {
return L.divIcon({
html: `
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
Expand All @@ -93,10 +101,10 @@ function Map({ entries }: { entries: Models.IEntry[] }) {
shadowUrl: null,
shadowSize: null,
shadowAnchor: null,
iconSize: [iconSize, iconSize],
iconAnchor: [iconSize / 2, iconSize / 2],
iconSize: [iconObj.iconSize, iconObj.iconSize],
iconAnchor: [iconObj.iconSize / 2, iconObj.iconSize / 2],
popupAnchor: [0, 0],
className: `customMarkerIcon ${className}`,
className: `customMarkerIcon ${iconObj.className}`,
});
}

Expand All @@ -114,11 +122,29 @@ function Map({ entries }: { entries: Models.IEntry[] }) {
return null;
};

function renderMarker(entry: Models.IEntry, iconObj: { className: string, iconSize: number }) {
return (
<Marker
key={entry.time.created}
position={[entry.lat, entry.lon]}
icon={createCustomIcon(entry, iconObj)}
rotationAngle={entry.heading}
rotationOrigin="center"
>
<Popup>
<pre>{JSON.stringify(entry, null, 2)}</pre>
</Popup>
</Marker>
)
}



return (
<div className="mapStyle" data-mui-color-scheme={mapStyle}>
<MapContainer className="mapContainer" center={[lastEntry.lat, lastEntry.lon]} zoom={13} maxZoom={19}>
<MapRecenter lat={lastEntry.lat} lon={lastEntry.lon} zoom={13} fly={true} />
<MapRecenter lat={lastEntry.lat} lon={lastEntry.lon} fly={true} />
<LocationButton lat={lastEntry.lat} lon={lastEntry.lon} />
<LayerChangeHandler />
<LayersControl position="bottomright">
{layers.map((layer, index) => {
Expand All @@ -142,40 +168,26 @@ function Map({ entries }: { entries: Models.IEntry[] }) {
</LayersControl>

<MarkerClusterGroup>
{cleanEntriesWithoutLast.map((entry) => {
return (
<Marker
key={entry.time.created}
position={[entry.lat, entry.lon]}
icon={createCustomIcon(entry)}
rotationAngle={entry.heading}
rotationOrigin="center"
>
<Popup>
<pre>{JSON.stringify(entry, null, 2)}</pre>
</Popup>
</Marker>
)
{cleanEntries.map((entry) => {
const iconObj = getClassName(entry);
if (iconObj.className != "none") { return } // exclude start and end from being in cluster group;

return renderMarker(entry, iconObj);
})}
</MarkerClusterGroup>


{/* lastEntry */}
<Marker
key={lastEntry.time.created}
position={[lastEntry.lat, lastEntry.lon]}
icon={createCustomIcon(lastEntry)}
rotationAngle={lastEntry.heading}
rotationOrigin="center"
>
<Popup>
<pre>{JSON.stringify(lastEntry, null, 2)}</pre>
</Popup>
</Marker>
{/* (re)start and end end markers */}
{cleanEntries.map((entry) => {
const iconObj = getClassName(entry);
if (iconObj.className == "none") { return } // exclude already rendered markers;

return renderMarker(entry, iconObj);
})}

<MultiColorPolyline cleanEntries={cleanEntries} />
</MapContainer>
</div>
</div >
)
}

Expand Down
6 changes: 3 additions & 3 deletions src/client/components/MapCenter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { useEffect } from 'react'
import { useMap } from "react-leaflet";

// Used to recenter the map to new coordinates
export const MapRecenter = ({ lat, lon, zoom, fly }: { lat: number, lon: number, zoom: number, fly: boolean }) => {
export const MapRecenter = ({ lat, lon, zoom, fly }: { lat: number, lon: number, zoom?: number, fly: boolean }) => {
const map = useMap();
useEffect(() => {
// Fly to that coordinates and set new zoom level
if (fly) {
map.flyTo([lat, lon], zoom);
map.flyTo([lat, lon], zoom || map.getZoom());
} else {
map.setView([lat, lon], zoom);
map.setView([lat, lon], zoom || map.getZoom());
}
}, [lat, lon]);
return null;
Expand Down
1 change: 1 addition & 0 deletions src/client/components/Status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ function getStatusData(entries) {
if (!eta) { return undefined }

const diffMinutes = (eta - lastEntry.time.created) / 60000;
if (diffMinutes <= 0) { return undefined; }
return diffMinutes >= 60 ? (diffMinutes / 60).toFixed(1) + ' hours' : diffMinutes.toFixed(1) + ' minutes';
}

Expand Down
32 changes: 26 additions & 6 deletions src/client/css/map.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

.leaflet-control-layers-base {
font-size: 1.4rem;

label {
cursor: pointer;
margin-bottom: 0.3em;
Expand All @@ -24,26 +24,37 @@
min-width: min-content;
}

.leaflet-overlay-pane canvas { /* polyline */
.leaflet-overlay-pane canvas {
/* polyline */
filter: drop-shadow(0px 0px 3px var(--neutral));
}

.marker-cluster[class] { /* overwrite default cluster style */
.marker-cluster[class] {
/* overwrite default cluster style */
background: none;

div {
background-color: var(--semiContrastBackground);
font-weight: bold;
box-shadow: inset 0 0 2px 2px var(--contrastBackground);

span {
color: var(--contrastText);
font-size: 1.5rem;
}
}
}

.easy-button-button {
&.active {
color: red;
}
}

.customMarkerIcon {

&.start, &.end {

&.start,
&.end {
display: flex;
place-content: center;
border: 2px solid var(--contrastBackground);
Expand All @@ -65,5 +76,14 @@
filter: drop-shadow(0 0 5px var(--contrastBackground));
}


&.geoLocation {
border-radius: 50%;
background: transparent;
color: var(--info);
border: none;
outline-color: currentColor;
outline-offset: 1px;
}


}
7 changes: 7 additions & 0 deletions src/client/css/start.css
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@
}

&.status {

@media (max-width: 35em) {
&.emptyData {
display: none;
}
}

grid-column: 2;
grid-row: 2;
margin: 1em 1em 1em 0;
Expand Down
Loading

0 comments on commit afb727e

Please sign in to comment.