Pretty nice (IMHO) version of avatars for locations...
This commit is contained in:
parent
9ce7f33cb4
commit
9bb2f48d4a
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import { locationOutline } from 'ionicons/icons';
|
||||
import React, { useId } from 'react';
|
||||
|
||||
import { useSelector } from 'react-redux';
|
||||
import { geoPoint, lat2tile, lon2tile, Point } from '../../lib/geo';
|
||||
|
@ -12,17 +13,15 @@ interface AvatarForLocationProps {
|
|||
zoom?: number;
|
||||
tileProvider?: string;
|
||||
size?: number;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
const AvatarForLocation: React.FC<AvatarForLocationProps> = (
|
||||
props: AvatarForLocationProps
|
||||
) => {
|
||||
const size = props.size ? props.size : 42;
|
||||
const size = props.size !== undefined ? 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),
|
||||
|
@ -34,10 +33,10 @@ const AvatarForLocation: React.FC<AvatarForLocationProps> = (
|
|||
y: 256 * (tilesLocation.y - Math.floor(tilesLocation.y)),
|
||||
};
|
||||
|
||||
const eastTileNeeded = locationWithinTile.x > 256 - size;
|
||||
const westTileNeeded = locationWithinTile.x < size;
|
||||
const southTileNeeded = locationWithinTile.y > 256 - size;
|
||||
const northTileNeeded = locationWithinTile.y < size;
|
||||
const eastTileNeeded = locationWithinTile.x > 256 - size / 2;
|
||||
const westTileNeeded = locationWithinTile.x < size / 2;
|
||||
const southTileNeeded = locationWithinTile.y > 256 - size / 2;
|
||||
const northTileNeeded = locationWithinTile.y < size / 2;
|
||||
|
||||
const getImage = (stepX: number, stepY: number) => (
|
||||
<image
|
||||
|
@ -48,8 +47,8 @@ const AvatarForLocation: React.FC<AvatarForLocationProps> = (
|
|||
)}
|
||||
height='256'
|
||||
width={256}
|
||||
x={-locationWithinTile.x + stepX * 256}
|
||||
y={-locationWithinTile.y + stepY * 256}
|
||||
x={-locationWithinTile.x + size / 2 + stepX * 256}
|
||||
y={-locationWithinTile.y + size / 2 + stepY * 256}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -81,19 +80,16 @@ const AvatarForLocation: React.FC<AvatarForLocationProps> = (
|
|||
|
||||
console.log(`${images.length} images: ${images}`);
|
||||
|
||||
const id = useId();
|
||||
|
||||
return (
|
||||
<svg width={size} height={size}>
|
||||
<defs>
|
||||
<clipPath id='cut-off'>
|
||||
<clipPath id={`cut-off-${id}`}>
|
||||
<circle cx={size / 2} cy={size / 2} r={size / 2} />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g clip-path='url(#cut-off)'>
|
||||
{[images]}
|
||||
<text x='2' y={size / 2 + 5} visibility='hidden'>
|
||||
{name}
|
||||
</text>
|
||||
</g>
|
||||
<g clip-path={`url(#cut-off-${id})`}>{[images]}</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -78,7 +78,7 @@ const LocationInfo: React.FC<{}> = () => {
|
|||
setNoteIndex(0);
|
||||
const metresPerDegree =
|
||||
111111 * Math.cos((scope.center.lat * Math.PI) / 180);
|
||||
const deltaDegrees = 2000 / metresPerDegree;
|
||||
const deltaDegrees = 5000 / metresPerDegree;
|
||||
const response = await fetch(
|
||||
`https://api.openstreetmap.org/api/0.6/notes.json?bbox=${
|
||||
scope.center.lon - deltaDegrees
|
||||
|
@ -89,6 +89,17 @@ const LocationInfo: React.FC<{}> = () => {
|
|||
);
|
||||
const data = await response.json();
|
||||
console.log(`notes: ${JSON.stringify(data)}`);
|
||||
data.features.sort(
|
||||
(first: any, second: any) =>
|
||||
roughDistance(scope.center, {
|
||||
lon: first.geometry.coordinates[0],
|
||||
lat: first.geometry.coordinates[1],
|
||||
}) >
|
||||
roughDistance(scope.center, {
|
||||
lon: second.geometry.coordinates[0],
|
||||
lat: second.geometry.coordinates[1],
|
||||
})
|
||||
);
|
||||
setNotes(data);
|
||||
};
|
||||
|
||||
|
@ -121,24 +132,23 @@ const LocationInfo: React.FC<{}> = () => {
|
|||
setNoteIndex(index);
|
||||
};
|
||||
|
||||
const AvatarForFeature: React.FC<{ feature: any; as: any }> = (props: {
|
||||
const AvatarForFeature: React.FC<{
|
||||
feature: any;
|
||||
size: number;
|
||||
as: any;
|
||||
}) => {
|
||||
}> = (props: { feature: any; size: number; as: any }) => {
|
||||
const distance = roughDistance(scope.center, {
|
||||
lon: props.feature.geometry.coordinates[0],
|
||||
lat: props.feature.geometry.coordinates[1],
|
||||
});
|
||||
const distDark = (255 * distance) / 3000;
|
||||
const distLight = 1 - distDark;
|
||||
return (
|
||||
<Avatar>
|
||||
<Avatar size={props.size <= 50 ? 'sm' : 'lg'}>
|
||||
<AvatarForLocation
|
||||
location={{
|
||||
lon: props.feature.geometry.coordinates[0],
|
||||
lat: props.feature.geometry.coordinates[1],
|
||||
}}
|
||||
name={Math.round(distance).toString()}
|
||||
size={props.size}
|
||||
/>
|
||||
</Avatar>
|
||||
);
|
||||
|
@ -205,25 +215,36 @@ const LocationInfo: React.FC<{}> = () => {
|
|||
<MainContainer responsive>
|
||||
<Sidebar position='left' id='chat-sidebar'>
|
||||
<ConversationList>
|
||||
{notes.features!.map((feature: any, index: number) => (
|
||||
<Conversation
|
||||
onClick={conversationClickHandlerFactory(index)}
|
||||
key={feature.properties.id}
|
||||
name={i18n.locationInfo!.at!(
|
||||
roughDistance(scope.center, {
|
||||
lon: feature.geometry.coordinates[0],
|
||||
lat: feature.geometry.coordinates[1],
|
||||
})
|
||||
)}
|
||||
info={feature.properties.status}
|
||||
>
|
||||
<AvatarForFeature feature={feature} as={Avatar} />
|
||||
</Conversation>
|
||||
))}
|
||||
{notes
|
||||
.features!.slice(0, 5)
|
||||
.map((feature: any, index: number) => (
|
||||
<Conversation
|
||||
onClick={conversationClickHandlerFactory(index)}
|
||||
key={feature.properties.id}
|
||||
name={i18n.locationInfo!.at!(
|
||||
roughDistance(scope.center, {
|
||||
lon: feature.geometry.coordinates[0],
|
||||
lat: feature.geometry.coordinates[1],
|
||||
})
|
||||
)}
|
||||
info={feature.properties.status}
|
||||
>
|
||||
<AvatarForFeature
|
||||
feature={feature}
|
||||
size={42}
|
||||
as={Avatar}
|
||||
/>
|
||||
</Conversation>
|
||||
))}
|
||||
</ConversationList>
|
||||
</Sidebar>
|
||||
<ChatContainer>
|
||||
<ConversationHeader>
|
||||
<AvatarForFeature
|
||||
feature={notes.features[noteIndex]}
|
||||
size={68}
|
||||
as={Avatar}
|
||||
/>
|
||||
<ConversationHeader.Content>
|
||||
<span
|
||||
style={{
|
||||
|
@ -240,10 +261,6 @@ const LocationInfo: React.FC<{}> = () => {
|
|||
)}
|
||||
</span>
|
||||
</ConversationHeader.Content>
|
||||
<AvatarForFeature
|
||||
feature={notes.features[noteIndex]}
|
||||
as={Avatar}
|
||||
/>
|
||||
</ConversationHeader>
|
||||
<MessageList>
|
||||
{noteIndex < notes.features.length &&
|
||||
|
|
|
@ -97,3 +97,8 @@ ion-modal ion-content {
|
|||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.cs-conversation-header__avatar {
|
||||
height: auto !important;
|
||||
width:auto !important;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue