diff --git a/src/components/map/Reticle.tsx b/src/components/map/Reticle.tsx index 1b98642..573cafc 100644 --- a/src/components/map/Reticle.tsx +++ b/src/components/map/Reticle.tsx @@ -1,26 +1,78 @@ +import _ from 'lodash'; import React from 'react'; import { useSelector } from 'react-redux'; import { Point } from '../../lib/geo'; import { MapState } from '../../store/map'; +import '../../theme/map.css'; const Reticle: React.FC<{}> = () => { - const windowState = useSelector( (state: { map: MapState }) => state.map.window ); + const scope = useSelector((state: { map: MapState }) => state.map.scope); + const radius = Math.min(windowState.width, windowState.height) / 4; + const center: Point = { + x: windowState.width / 2, + y: windowState.height / 2, + }; - const center: Point = { x: windowState.width / 2, y: windowState.height / 2 }; - const radius = Math.min(windowState.width, windowState.height) / 6; + /** + * The horizontal distance represented by each square tile, measured along the parallel at a given latitude, is given by: + * Stile = C ∙ cos(latitude) / 2 zoomlevel + * As tiles are 256-pixels wide, the horizontal distance represented by one pixel is: + * Spixel = Stile / 256 = C ∙ cos(latitude) / 2 (zoomlevel + 8) + * where C means the equatorial circumference of the Earth (40 075 016.686 m ≈ 2π ∙ 6 378 137.000 m for the reference geoid used by OpenStreetMap). + * see https://wiki.openstreetmap.org/wiki/Zoom_levels + */ + + const sTile = + (40075016.686 * Math.cos((scope.center.lat * Math.PI) / 180)) / + 2 ** scope.zoom; + + const radiusMeters = (sTile * radius) / 256; + const radiusOrder = Math.floor(Math.log10(radiusMeters)); + const radiusRoughUnit = radiusMeters / 10 ** radiusOrder; + var radiusBaseUnit, radiusBaseSubUnit; + if (radiusRoughUnit <= 2) { + radiusBaseUnit = 1; + radiusBaseSubUnit = 0.2; + } else if (radiusRoughUnit <= 5) { + radiusBaseUnit = 2; + radiusBaseSubUnit = 0.5; + } else { + radiusBaseUnit = 5; + radiusBaseSubUnit = 1; + } + + const nbSubUnits = Math.floor( + radiusMeters / (radiusBaseSubUnit * 10 ** radiusOrder) + ); + const nbUnits = Math.floor( + radiusMeters / (radiusBaseUnit * 10 ** radiusOrder) + ); + + const radiusUnit = radiusOrder < 3 ? 'm' : 'km'; + const radiusUnitValue = + radiusOrder < 3 + ? radiusBaseUnit * 10 ** radiusOrder + : radiusBaseUnit * 10 ** (radiusOrder - 3); + + const subUnitPxStep = ((radiusBaseSubUnit * 10 ** radiusOrder) / sTile) * 256; + const unitPxStep = ((radiusBaseUnit * 10 ** radiusOrder) / sTile) * 256; + + console.log( + `radiusMeters: ${radiusMeters}, radiusOrder: ${radiusOrder}, radiusUnit: ${radiusBaseUnit}, radiusSubUnit: ${radiusBaseSubUnit}, nbSubUnits: ${nbSubUnits}` + ); return ( - + = () => { v ${radius - 3} m 0,${6} v ${radius - 3}`} - strokeWidth={1} - stroke='red' + strokeWidth={0.5} /> + + `M ${center.x + i * subUnitPxStep},${center.y - 10} v 20` + ) + .join(' ')} + /> + `M ${center.x + i * unitPxStep},${center.y - 20} v 40`) + .join(' ')} + strokeWidth={0.5} + /> + + + + + + {`${radiusUnitValue} ${radiusUnit}`} + ); }; diff --git a/src/theme/map.css b/src/theme/map.css index 0ce4b14..e44b719 100644 --- a/src/theme/map.css +++ b/src/theme/map.css @@ -43,6 +43,17 @@ path.current { stroke: rgba(2, 71, 20, 0.8); } +.reticle path, +path.reticle, +use.reticle, +.reticle use { + stroke: red; +} + +.reticle text { + font-size: 12px; +} + ion-modal { --height: 50%; --border-radius: 16px; @@ -60,14 +71,13 @@ ion-modal.full-height { } */ ion-modal ion-toolbar { - --background: rgba(14,116,144, .7); + --background: rgba(14, 116, 144, 0.7); --color: white; } ion-modal.full-height ion-toolbar { - --background: rgba(14,116,144, 1); - } - + --background: rgba(14, 116, 144, 1); +} ion-modal ion-toolbar.secondary { --background: inherit; @@ -75,10 +85,9 @@ ion-modal ion-toolbar.secondary { } ion-modal ion-content { - background-color: rgba(255,255,255,.7) - ; + background-color: rgba(255, 255, 255, 0.7); } .hidden { display: none; -} \ No newline at end of file +}