diff --git a/src/_modules/InteractivePoly.ts b/src/_modules/InteractivePoly.ts index 632d03e..2d021ab 100644 --- a/src/_modules/InteractivePoly.ts +++ b/src/_modules/InteractivePoly.ts @@ -18,7 +18,7 @@ import { LatLngLiteral } from "leaflet"; -import { distKm, distToSegment, getPolyLength, pointInArea } from "~/utils/geom"; +import { distKmHaversine, distToSegment, getPolyLength, pointInArea } from "~/utils/geom"; interface InteractivePolylineOptions extends PolylineOptions { maxMarkers?: number; @@ -271,11 +271,11 @@ export class InteractivePoly extends Polyline { const prev = this.markers[index]; const next = this.markers[index + 1]; - const initial_distance = distKm(prev.getLatLng(), next.getLatLng()); + const initial_distance = distKmHaversine(prev.getLatLng(), next.getLatLng()); const current_distance = - ((prev && distKm(prev.getLatLng(), current)) || 0) + - ((next && distKm(next.getLatLng(), current)) || 0); + ((prev && distKmHaversine(prev.getLatLng(), current)) || 0) + + ((next && distKmHaversine(next.getLatLng(), current)) || 0); this.distance += current_distance - initial_distance; @@ -377,12 +377,12 @@ export class InteractivePoly extends Polyline { index <= this.markers.length + 1 ? this.markers[index + 1] : null; const initial_distance = - ((prev && distKm(prev.getLatLng(), initial)) || 0) + - ((next && distKm(next.getLatLng(), initial)) || 0); + ((prev && distKmHaversine(prev.getLatLng(), initial)) || 0) + + ((next && distKmHaversine(next.getLatLng(), initial)) || 0); const current_distance = - ((prev && distKm(prev.getLatLng(), current)) || 0) + - ((next && distKm(next.getLatLng(), current)) || 0); + ((prev && distKmHaversine(prev.getLatLng(), current)) || 0) + + ((next && distKmHaversine(next.getLatLng(), current)) || 0); this.distance += current_distance - initial_distance; @@ -460,7 +460,7 @@ export class InteractivePoly extends Polyline { ? latlngs[latlngs.length - 1] : latlngs[0]; - this.distance += distKm(point, latlng); + this.distance += distKmHaversine(point, latlng); this.fire("distancechange", { distance: this.distance }); }; @@ -505,10 +505,10 @@ export class InteractivePoly extends Polyline { const next = index <= latlngs.length + 1 ? latlngs[index + 1] : null; const initial_distance = - ((prev && distKm(prev, current)) || 0) + - ((next && distKm(next, current)) || 0); + ((prev && distKmHaversine(prev, current)) || 0) + + ((next && distKmHaversine(next, current)) || 0); - const current_distance = (prev && next && distKm(prev, next)) || 0; + const current_distance = (prev && next && distKmHaversine(prev, next)) || 0; this.distance += current_distance - initial_distance; diff --git a/src/_modules/KmMarks.ts b/src/_modules/KmMarks.ts index 7e25910..d44aa70 100644 --- a/src/_modules/KmMarks.ts +++ b/src/_modules/KmMarks.ts @@ -1,7 +1,7 @@ import { divIcon, LatLngLiteral, Layer, LayerGroup, Map, marker, Marker } from "leaflet"; import { arrowClusterIcon, createArrow } from "~/utils/arrow"; import { MarkerClusterGroup } from 'leaflet.markercluster/dist/leaflet.markercluster-src.js'; -import { allwaysPositiveAngleDeg, angleBetweenPoints, distKm } from "~/utils/geom"; +import { allwaysPositiveAngleDeg, angleBetweenPoints, distKmHaversine } from "~/utils/geom"; import classNames from 'classnames'; interface KmMarksOptions { @@ -43,7 +43,7 @@ class Component extends LayerGroup { if (index >= latlngs.length - 1) return dist; const next = latlngs[index + 1]; - const diff = distKm(current, next); + const diff = distKmHaversine(current, next); const sum = dist + diff; const rounded = Math.floor(sum / this.options.kmMarksStep) * this.options.kmMarksStep; const count = Math.floor((rounded - last_km_mark) / this.options.kmMarksStep); diff --git a/src/constants/map.ts b/src/constants/map.ts index ca1e9f7..61b47cc 100644 --- a/src/constants/map.ts +++ b/src/constants/map.ts @@ -1,4 +1,4 @@ -import { Map, LayerGroup, Layer, FeatureGroup } from 'leaflet'; +import { Map, FeatureGroup, FitBoundsOptions } from 'leaflet'; export class MapContainer extends Map { constructor(props) { @@ -21,8 +21,16 @@ export class MapContainer extends Map { const bounds = layers[i].getBounds(); if (Object.keys(bounds).length == 2) return bounds; } + return null; }; + fitVisibleBounds = (options: FitBoundsOptions) => { + const bounds = this.getVisibleBounds(); + + if (!bounds) return; + this.fitBounds(bounds, options) + } + public clickable = true; public routeLayer = new FeatureGroup(); diff --git a/src/redux/editor/sagas.ts b/src/redux/editor/sagas.ts index 7a13e07..4d58586 100644 --- a/src/redux/editor/sagas.ts +++ b/src/redux/editor/sagas.ts @@ -183,7 +183,7 @@ function* locationChangeSaga({ location }: ReturnType) { diff --git a/src/redux/map/sagas.ts b/src/redux/map/sagas.ts index f91d52a..65df3bd 100644 --- a/src/redux/map/sagas.ts +++ b/src/redux/map/sagas.ts @@ -29,8 +29,7 @@ import { editorSetSave, editorClearAll, } from '~/redux/editor/actions'; -import { pushLoaderState, getUrlData, pushPath, replacePath } from '~/utils/history'; -import { searchSetSagaWorker } from '~/redux/user/sagas'; +import { pushLoaderState, getUrlData, pushPath } from '~/utils/history'; import { getStoredMap, postMap } from '~/utils/api'; import { Unwrap } from '~/utils/middleware'; import { selectMap, selectMapProvider } from './selectors'; @@ -150,7 +149,7 @@ export function* mapInitSaga() { yield call(loadMapFromPath); yield call(setReadySaga); - MainMap.fitBounds(MainMap.getVisibleBounds(), { animate: false }); + MainMap.fitVisibleBounds({ animate: false }); pushLoaderState(100); } diff --git a/src/utils/geom.ts b/src/utils/geom.ts index 6517084..b3120ad 100644 --- a/src/utils/geom.ts +++ b/src/utils/geom.ts @@ -1,25 +1,26 @@ -import { LatLng, LatLngLiteral, point, Point, PointExpression } from "leaflet"; +import { LatLng, LatLngLiteral, point, Point, PointExpression } from 'leaflet'; interface ILatLng { - lat: number, - lng: number, + lat: number; + lng: number; } export const middleCoord = (l1: ILatLng, l2: ILatLng): ILatLng => ({ - lat: (l2.lat + ((l1.lat - l2.lat) / 2)), - lng: (l2.lng + ((l1.lng - l2.lng) / 2)) + lat: l2.lat + (l1.lat - l2.lat) / 2, + lng: l2.lng + (l1.lng - l2.lng) / 2, }); -export const middleCoordPx = (p1: Point, p2: Point): Point => point({ - x: (p1.x + ((p2.x - p1.x) / 2)), - y: (p1.y + ((p2.y - p1.y) / 2)) -}); +export const middleCoordPx = (p1: Point, p2: Point): Point => + point({ + x: p1.x + (p2.x - p1.x) / 2, + y: p1.y + (p2.y - p1.y) / 2, + }); -export const deg2rad = (deg: number): number => ((deg * Math.PI) / 180); -export const rad2deg = (rad: number): number => ((rad / Math.PI) * 180); +export const deg2rad = (deg: number): number => (deg * Math.PI) / 180; +export const rad2deg = (rad: number): number => (rad / Math.PI) * 180; export const findDistancePx = (p1: Point, p2: Point): number => { - return Math.sqrt(((p1.x - p2.x) ** 2) + ((p1.y - p2.y) ** 2)); + return Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2); }; export const findDistance = (t1: number, n1: number, t2: number, n2: number): number => { @@ -34,40 +35,56 @@ export const findDistance = (t1: number, n1: number, t2: number, n2: number): nu const dlon = lon2 - lon1; // here's the heavy lifting - const a = (Math.sin(dlat / 2) ** 2) + - (Math.cos(lat1) * Math.cos(lat2) * (Math.sin(dlon / 2) ** 2)); + const a = Math.sin(dlat / 2) ** 2 + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dlon / 2) ** 2; const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); // great circle distance in radians const dk = c * 6373; // great circle distance in km - return (Math.round(dk * 1000) / 1000); + return Math.round(dk * 1000) / 1000; }; -export const distKm = (A: LatLngLiteral, B: LatLngLiteral): number => findDistance(A.lat, A.lng, B.lat, B.lng); +// probably faster one +export const findDistanceHaversine = (t1: number, n1: number, t2: number, n2: number): number => { + const R = 6371; // km + const dLat = ((t2 - t1) * Math.PI) / 180; + var dLon = ((n2 - n1) * Math.PI) / 180; + var a = + Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos((t1 * Math.PI) / 180) * + Math.cos((t2 * Math.PI) / 180) * + Math.sin(dLon / 2) * + Math.sin(dLon / 2); + var c = 2 * Math.asin(Math.sqrt(a)); + return R * c; +}; -export const getLabelDirection = (angle: number): 'left' | 'right' => ( - ((angle % Math.PI) >= -(Math.PI / 2) && (angle % Math.PI) <= (Math.PI / 2)) ? 'left' : 'right' -); +export const distKm = (A: LatLngLiteral, B: LatLngLiteral): number => + findDistance(A.lat, A.lng, B.lat, B.lng); + +export const distKmHaversine = (A: LatLngLiteral, B: LatLngLiteral): number => + findDistanceHaversine(A.lat, A.lng, B.lat, B.lng); + +export const getLabelDirection = (angle: number): 'left' | 'right' => + angle % Math.PI >= -(Math.PI / 2) && angle % Math.PI <= Math.PI / 2 ? 'left' : 'right'; export const getPolyLength = (latlngs: LatLngLiteral[]): number => { if (latlngs.length < 2) return 0; - return latlngs.reduce((dist, item, index) => ( - index < (latlngs.length - 1) - ? dist + distKm(item, latlngs[index + 1]) - : dist - ), 0) + return latlngs.reduce( + (dist, item, index) => + index < latlngs.length - 1 ? dist + distKmHaversine(item, latlngs[index + 1]) : dist, + 0 + ); }; // if C between A and B -export const pointInArea = (A: LatLng, B: LatLng, C: LatLng, radius: number = 0.001): boolean => ( +export const pointInArea = (A: LatLng, B: LatLng, C: LatLng, radius: number = 0.001): boolean => C.lng <= Math.max(A.lng + radius, B.lng + radius) && C.lat <= Math.max(A.lat + radius, B.lat + radius) && C.lat >= Math.min(A.lat - radius, B.lat - radius) && - C.lng >= Math.min(A.lng - radius, B.lng - radius) -); + C.lng >= Math.min(A.lng - radius, B.lng - radius); - -export const dist2 = (A: LatLngLiteral, B: LatLngLiteral): number => (((A.lat - B.lat) ** 2) + ((A.lng - B.lng) ** 2)); +export const dist2 = (A: LatLngLiteral, B: LatLngLiteral): number => + (A.lat - B.lat) ** 2 + (A.lng - B.lng) ** 2; const distToSegmentSquared = (A: LatLng, B: LatLng, C: LatLng): number => { const l2 = dist2(A, B); @@ -75,29 +92,27 @@ const distToSegmentSquared = (A: LatLng, B: LatLng, C: LatLng): number => { const t = Math.max( 0, - Math.min( - 1, - (((C.lat - A.lat) * (B.lat - A.lat) + (C.lng - A.lng) * (B.lng - A.lng)) / l2) - ) + Math.min(1, ((C.lat - A.lat) * (B.lat - A.lat) + (C.lng - A.lng) * (B.lng - A.lng)) / l2) ); - return dist2( - C, - { - lat: A.lat + t * (B.lat - A.lat), - lng: A.lng + t * (B.lng - A.lng) - }); + return dist2(C, { + lat: A.lat + t * (B.lat - A.lat), + lng: A.lng + t * (B.lng - A.lng), + }); }; -export const distToSegment = (A: LatLng, B: LatLng, C: LatLng): number => Math.sqrt(distToSegmentSquared(A, B, C)); +export const distToSegment = (A: LatLng, B: LatLng, C: LatLng): number => + Math.sqrt(distToSegmentSquared(A, B, C)); -export const pointBetweenPoints = (A: LatLng, B: LatLng, C: LatLng): boolean => (distToSegment(A, B, C) < 0.01); +export const pointBetweenPoints = (A: LatLng, B: LatLng, C: LatLng): boolean => + distToSegment(A, B, C) < 0.01; -export const angleBetweenPoints = (A: Point, B: Point): number => parseFloat(((Math.atan2(B.y - A.y, B.x - A.x))* 180 / Math.PI).toFixed()); -export const angleBetweenPointsRad = (A: Point, B: Point): number => ((Math.atan2(B.x - A.x, B.y - A.y))); +export const angleBetweenPoints = (A: Point, B: Point): number => + parseFloat(((Math.atan2(B.y - A.y, B.x - A.x) * 180) / Math.PI).toFixed()); +export const angleBetweenPointsRad = (A: Point, B: Point): number => + Math.atan2(B.x - A.x, B.y - A.y); -export const allwaysPositiveAngleDeg = (angle: number): number => ( - (angle >= -90 && angle <= 90) ? angle : (180 + angle) -); +export const allwaysPositiveAngleDeg = (angle: number): number => + angle >= -90 && angle <= 90 ? angle : 180 + angle; -export const nearestInt = (value: number, parts: number): number => (value - (value % parts)); +export const nearestInt = (value: number, parts: number): number => value - (value % parts); diff --git a/src/utils/marks.ts b/src/utils/marks.ts index 6ab49dc..bd6b147 100644 --- a/src/utils/marks.ts +++ b/src/utils/marks.ts @@ -1,7 +1,7 @@ import { divIcon, LatLngLiteral, Layer, LayerGroup, Map, marker, Marker } from "leaflet"; import { arrowClusterIcon, createArrow } from "~/utils/arrow"; import { MarkerClusterGroup } from 'leaflet.markercluster/dist/leaflet.markercluster-src.js'; -import { allwaysPositiveAngleDeg, angleBetweenPoints, distKm } from "~/utils/geom"; +import { allwaysPositiveAngleDeg, angleBetweenPoints, distKmHaversine } from "~/utils/geom"; import classNames from 'classnames'; interface KmMarksOptions { @@ -43,7 +43,7 @@ class KmMarksLayer extends LayerGroup { if (index >= latlngs.length - 1) return dist; const next = latlngs[index + 1]; - const diff = distKm(current, next); + const diff = distKmHaversine(current, next); const sum = dist + diff; const rounded = Math.floor(sum / this.options.kmMarksStep) * this.options.kmMarksStep; const count = Math.floor((rounded - last_km_mark) / this.options.kmMarksStep); @@ -72,7 +72,6 @@ class KmMarksLayer extends LayerGroup { return sum; }, 0); - }; createMiddleMarker = (latlng: LatLngLiteral, angle: number, distance: number): Marker => marker(latlng, { diff --git a/src/utils/polyline.ts b/src/utils/polyline.ts index 7c8c23c..f209dd2 100644 --- a/src/utils/polyline.ts +++ b/src/utils/polyline.ts @@ -18,7 +18,7 @@ import { LatLngLiteral, } from 'leaflet'; -import { distKm, distToSegment, getPolyLength, pointInArea } from '~/utils/geom'; +import { distKmHaversine, distToSegment, getPolyLength, pointInArea } from '~/utils/geom'; interface InteractivePolylineOptions extends PolylineOptions { maxMarkers?: number; @@ -268,11 +268,11 @@ export class InteractivePoly extends Polyline { const prev = this.markers[index]; const next = this.markers[index + 1]; - const initial_distance = distKm(prev.getLatLng(), next.getLatLng()); + const initial_distance = distKmHaversine(prev.getLatLng(), next.getLatLng()); const current_distance = - ((prev && distKm(prev.getLatLng(), current)) || 0) + - ((next && distKm(next.getLatLng(), current)) || 0); + ((prev && distKmHaversine(prev.getLatLng(), current)) || 0) + + ((next && distKmHaversine(next.getLatLng(), current)) || 0); this.distance += current_distance - initial_distance; @@ -369,12 +369,12 @@ export class InteractivePoly extends Polyline { const next = index <= this.markers.length + 1 ? this.markers[index + 1] : null; const initial_distance = - ((prev && distKm(prev.getLatLng(), initial)) || 0) + - ((next && distKm(next.getLatLng(), initial)) || 0); + ((prev && distKmHaversine(prev.getLatLng(), initial)) || 0) + + ((next && distKmHaversine(next.getLatLng(), initial)) || 0); const current_distance = - ((prev && distKm(prev.getLatLng(), current)) || 0) + - ((next && distKm(next.getLatLng(), current)) || 0); + ((prev && distKmHaversine(prev.getLatLng(), current)) || 0) + + ((next && distKmHaversine(next.getLatLng(), current)) || 0); this.distance += current_distance - initial_distance; @@ -448,7 +448,7 @@ export class InteractivePoly extends Polyline { const point = this.drawing_direction === 'forward' ? latlngs[latlngs.length - 1] : latlngs[0]; - this.distance += distKm(point, latlng); + this.distance += distKmHaversine(point, latlng); this.fire('distancechange', { distance: this.distance }); }; @@ -493,9 +493,9 @@ export class InteractivePoly extends Polyline { const next = index <= latlngs.length + 1 ? latlngs[index + 1] : null; const initial_distance = - ((prev && distKm(prev, current)) || 0) + ((next && distKm(next, current)) || 0); + ((prev && distKmHaversine(prev, current)) || 0) + ((next && distKmHaversine(next, current)) || 0); - const current_distance = (prev && next && distKm(prev, next)) || 0; + const current_distance = (prev && next && distKmHaversine(prev, next)) || 0; this.distance += current_distance - initial_distance;