Still playing with the reticle...
This commit is contained in:
parent
77f5ab3996
commit
27305c4b21
|
@ -1,26 +1,78 @@
|
||||||
|
import _ from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { Point } from '../../lib/geo';
|
import { Point } from '../../lib/geo';
|
||||||
import { MapState } from '../../store/map';
|
import { MapState } from '../../store/map';
|
||||||
|
import '../../theme/map.css';
|
||||||
|
|
||||||
const Reticle: React.FC<{}> = () => {
|
const Reticle: React.FC<{}> = () => {
|
||||||
|
|
||||||
const windowState = useSelector(
|
const windowState = useSelector(
|
||||||
(state: { map: MapState }) => state.map.window
|
(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 (
|
return (
|
||||||
<g>
|
<g className='reticle'>
|
||||||
<circle
|
<circle
|
||||||
cx={center.x}
|
cx={center.x}
|
||||||
cy={center.y}
|
cy={center.y}
|
||||||
r={radius}
|
r={radius}
|
||||||
fill='transparent'
|
fill='transparent'
|
||||||
stroke='black'
|
stroke='black'
|
||||||
strokeWidth={2}
|
strokeWidth={1}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={`M ${center.x - radius},${center.y}
|
d={`M ${center.x - radius},${center.y}
|
||||||
|
@ -31,9 +83,39 @@ const Reticle: React.FC<{}> = () => {
|
||||||
v ${radius - 3}
|
v ${radius - 3}
|
||||||
m 0,${6}
|
m 0,${6}
|
||||||
v ${radius - 3}`}
|
v ${radius - 3}`}
|
||||||
strokeWidth={1}
|
strokeWidth={0.5}
|
||||||
stroke='red'
|
|
||||||
/>
|
/>
|
||||||
|
<g id='reticle-east'>
|
||||||
|
<path stroke='red' className='reticle'
|
||||||
|
strokeWidth={0.5}
|
||||||
|
d={_.range(1, nbSubUnits + 1)
|
||||||
|
.map(
|
||||||
|
(i) => `M ${center.x + i * subUnitPxStep},${center.y - 10} v 20`
|
||||||
|
)
|
||||||
|
.join(' ')}
|
||||||
|
/>
|
||||||
|
<path stroke='red' className='reticle'
|
||||||
|
d={_.range(1, nbUnits + 1)
|
||||||
|
.map((i) => `M ${center.x + i * unitPxStep},${center.y - 20} v 40`)
|
||||||
|
.join(' ')}
|
||||||
|
strokeWidth={0.5}
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<use stroke='red' className='reticle'
|
||||||
|
href='#reticle-east'
|
||||||
|
transform={`rotate(90, ${center.x}, ${center.y})`}
|
||||||
|
/>
|
||||||
|
<use className='reticle'
|
||||||
|
href='#reticle-east'
|
||||||
|
transform={`rotate(180, ${center.x}, ${center.y})`}
|
||||||
|
/>
|
||||||
|
<use className='reticle'
|
||||||
|
href='#reticle-east'
|
||||||
|
transform={`rotate(-90, ${center.x}, ${center.y})`}
|
||||||
|
/>
|
||||||
|
<text x={center.x + unitPxStep - 15} y={center.y - 20}>
|
||||||
|
{`${radiusUnitValue} ${radiusUnit}`}
|
||||||
|
</text>
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,6 +43,17 @@ path.current {
|
||||||
stroke: rgba(2, 71, 20, 0.8);
|
stroke: rgba(2, 71, 20, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.reticle path,
|
||||||
|
path.reticle,
|
||||||
|
use.reticle,
|
||||||
|
.reticle use {
|
||||||
|
stroke: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reticle text {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
ion-modal {
|
ion-modal {
|
||||||
--height: 50%;
|
--height: 50%;
|
||||||
--border-radius: 16px;
|
--border-radius: 16px;
|
||||||
|
@ -60,14 +71,13 @@ ion-modal.full-height {
|
||||||
} */
|
} */
|
||||||
|
|
||||||
ion-modal ion-toolbar {
|
ion-modal ion-toolbar {
|
||||||
--background: rgba(14,116,144, .7);
|
--background: rgba(14, 116, 144, 0.7);
|
||||||
--color: white;
|
--color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-modal.full-height ion-toolbar {
|
ion-modal.full-height ion-toolbar {
|
||||||
--background: rgba(14,116,144, 1);
|
--background: rgba(14, 116, 144, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ion-modal ion-toolbar.secondary {
|
ion-modal ion-toolbar.secondary {
|
||||||
--background: inherit;
|
--background: inherit;
|
||||||
|
@ -75,8 +85,7 @@ ion-modal ion-toolbar.secondary {
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-modal ion-content {
|
ion-modal ion-content {
|
||||||
background-color: rgba(255,255,255,.7)
|
background-color: rgba(255, 255, 255, 0.7);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
|
|
Loading…
Reference in New Issue