Starting to implement avatars for locations (WIP).

This commit is contained in:
Eric van der Vlist 2022-10-11 17:38:23 +02:00
parent 6954c473ee
commit d1da0a110d
3 changed files with 73 additions and 23 deletions

View File

@ -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;

View File

@ -32,6 +32,8 @@ import { useSelector } from 'react-redux';
import i18n from '../../i18n';
import { geoPoint } from '../../lib/geo';
import { MapState } from '../../store/map';
import AvatarForLocation from './AvatarForLocation';
import { round } from 'lodash';
const LocationInfo: React.FC<{}> = () => {
const scope = useSelector((state: { map: MapState }) => state.map.scope);
@ -134,17 +136,15 @@ const LocationInfo: React.FC<{}> = () => {
const distDark = (255 * distance) / 3000;
const distLight = 1 - distDark;
return (
<Avatar
src={AvatarInitial.initialAvatar({
size: 100,
initials: Math.round(distance),
initial_fg: `rgb(${distLight},0,${distLight}`,
initial_bg: `rgb(0,${distDark}, 0`,
initial_size: 33, // Defaults to height / 2
initial_weight: 1000,
initial_font_family: "'Lato', 'Lato-Regular', 'Helvetica Neue'",
})}
/>
<Avatar>
<AvatarForLocation
location={{
lon: props.feature.geometry.coordinates[0],
lat: props.feature.geometry.coordinates[1],
}}
name={Math.round(distance).toString()}
/>
</Avatar>
);
};

View File

@ -15,6 +15,18 @@ import {
import i18n from '../../i18n';
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 windowState = useSelector(
(state: { map: MapState }) => state.map.window
@ -26,18 +38,7 @@ const Reticle: React.FC<{}> = () => {
y: windowState.height / 2,
};
/**
* 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 sTile = getSTile(scope.center.lat, scope.zoom);
const radiusMeters = (sTile * radius) / 256;
const radiusOrder = Math.floor(Math.log10(radiusMeters));