Starting to implement avatars for locations (WIP).
This commit is contained in:
parent
6954c473ee
commit
d1da0a110d
|
@ -0,0 +1,49 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { geoPoint, lat2tile, lon2tile, Point } from '../../lib/geo';
|
||||||
|
|
||||||
|
import { MapState } from '../../store/map';
|
||||||
|
import { tileProviders } from './tile';
|
||||||
|
|
||||||
|
interface AvatarForLocationProps {
|
||||||
|
location: geoPoint;
|
||||||
|
zoom?: number;
|
||||||
|
tileProvider?: string;
|
||||||
|
size?: number;
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AvatarForLocation: React.FC<AvatarForLocationProps> = (
|
||||||
|
props: AvatarForLocationProps
|
||||||
|
) => {
|
||||||
|
const size = props.size ? props.size : 42;
|
||||||
|
const zoom = props.zoom ? Math.round(props.zoom) : 16;
|
||||||
|
const tileProvider = props.tileProvider ? props.tileProvider : 'osm';
|
||||||
|
const location = props.location;
|
||||||
|
const name = props.name ? props.name : '???';
|
||||||
|
|
||||||
|
const tilesLocation: Point = {
|
||||||
|
x: lon2tile(location.lon, zoom),
|
||||||
|
y: lat2tile(location.lat, zoom),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg width={size} height={size}>
|
||||||
|
<defs>
|
||||||
|
<clipPath id='cut-off'>
|
||||||
|
<circle cx={size / 2} cy={size / 2} r={size / 2} />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<g clip-path='url(#cut-off)'>
|
||||||
|
<image href={tileProviders[tileProvider].getTileUrl(zoom, Math.floor(tilesLocation.x), Math.floor(tilesLocation.y))} />
|
||||||
|
<text x='2' y={size / 2 + 5}>
|
||||||
|
{name}
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AvatarForLocation;
|
|
@ -32,6 +32,8 @@ import { useSelector } from 'react-redux';
|
||||||
import i18n from '../../i18n';
|
import i18n from '../../i18n';
|
||||||
import { geoPoint } from '../../lib/geo';
|
import { geoPoint } from '../../lib/geo';
|
||||||
import { MapState } from '../../store/map';
|
import { MapState } from '../../store/map';
|
||||||
|
import AvatarForLocation from './AvatarForLocation';
|
||||||
|
import { round } from 'lodash';
|
||||||
|
|
||||||
const LocationInfo: React.FC<{}> = () => {
|
const LocationInfo: React.FC<{}> = () => {
|
||||||
const scope = useSelector((state: { map: MapState }) => state.map.scope);
|
const scope = useSelector((state: { map: MapState }) => state.map.scope);
|
||||||
|
@ -134,17 +136,15 @@ const LocationInfo: React.FC<{}> = () => {
|
||||||
const distDark = (255 * distance) / 3000;
|
const distDark = (255 * distance) / 3000;
|
||||||
const distLight = 1 - distDark;
|
const distLight = 1 - distDark;
|
||||||
return (
|
return (
|
||||||
<Avatar
|
<Avatar>
|
||||||
src={AvatarInitial.initialAvatar({
|
<AvatarForLocation
|
||||||
size: 100,
|
location={{
|
||||||
initials: Math.round(distance),
|
lon: props.feature.geometry.coordinates[0],
|
||||||
initial_fg: `rgb(${distLight},0,${distLight}`,
|
lat: props.feature.geometry.coordinates[1],
|
||||||
initial_bg: `rgb(0,${distDark}, 0`,
|
}}
|
||||||
initial_size: 33, // Defaults to height / 2
|
name={Math.round(distance).toString()}
|
||||||
initial_weight: 1000,
|
|
||||||
initial_font_family: "'Lato', 'Lato-Regular', 'Helvetica Neue'",
|
|
||||||
})}
|
|
||||||
/>
|
/>
|
||||||
|
</Avatar>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,18 @@ import {
|
||||||
import i18n from '../../i18n';
|
import i18n from '../../i18n';
|
||||||
import eventBus from '../../lib/pubsub';
|
import eventBus from '../../lib/pubsub';
|
||||||
|
|
||||||
|
export const getSTile = (lat: number, zoom: number) => {
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
return (40075016.686 * Math.cos((lat * Math.PI) / 180)) / 2 ** zoom;
|
||||||
|
};
|
||||||
|
|
||||||
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
|
||||||
|
@ -26,18 +38,7 @@ const Reticle: React.FC<{}> = () => {
|
||||||
y: windowState.height / 2,
|
y: windowState.height / 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
const sTile = getSTile(scope.center.lat, scope.zoom);
|
||||||
* 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 radiusMeters = (sTile * radius) / 256;
|
||||||
const radiusOrder = Math.floor(Math.log10(radiusMeters));
|
const radiusOrder = Math.floor(Math.log10(radiusMeters));
|
||||||
|
|
Loading…
Reference in New Issue