dyomedea/src/components/infos/Infos.tsx

302 lines
11 KiB
TypeScript

import { Button, IconButton } from '@suid/material';
import { Feature } from 'ol';
import { Geometry } from 'ol/geom';
import { Component, createSignal, For, Match, Show, Switch } from 'solid-js';
import { useI18n } from '@solid-primitives/i18n';
import TravelExploreIcon from '@suid/icons-material/TravelExplore';
import AddLocationAltIcon from '@suid/icons-material/AddLocationAlt';
import OpenInNewIcon from '@suid/icons-material/OpenInNew';
import CallIcon from '@suid/icons-material/Call';
import { Paper, Stack } from '@suid/material';
import styled from '@suid/material/styles/styled';
import Dialog from '../dialog';
import Tree from '../tree';
import { GpxViewer } from '../gpx';
import { Browser } from '@capacitor/browser';
import { isHighlightedTagType } from '../map-tile-provider/MapTileProvider';
import style from '../gpx/styles';
import OsmFindAll from './OsmFindAll';
import { toLonLat } from 'ol/proj';
import { getTagType } from '../overlays/overlay-definitions';
const Item = styled(Paper)(({ theme }) => ({
...theme.typography.body2,
padding: theme.spacing(1),
textAlign: 'center',
color: theme.palette.text.secondary,
}));
const [open, setOpen] = createSignal(false);
const [location, setLocation] = createSignal();
let selectedFeatures: Feature[] = [];
let vectorLayerFeatures: Feature[] = [];
let hierarchy: any = {};
const level2Key = (feature: Feature) =>
feature.get('context').wptId ||
feature.get('context').rteId ||
feature.get('context').trkId;
export const clickHandler = (event: any) => {
hierarchy = {};
const map = event.map;
const pixel = [event.originalEvent.x, event.originalEvent.y];
const features = map.getFeaturesAtPixel(pixel, { hitTolerance: 30 });
setLocation(toLonLat(map.getCoordinateFromPixel(pixel)));
console.log({ caller: 'Infos.tsx / clickHandler', features, event });
selectedFeatures.map((feature) => {
if (feature.set) {
feature.set('isSelected', false);
}
});
selectedFeatures = features.filter((feature: any) => feature.get('context'));
let osmIds = new Set<string>();
vectorLayerFeatures = features.filter((feature: any) => {
if (feature.get('context')) {
return false;
}
const osmId = feature.get('osm_id');
if (osmIds.has(osmId)) {
return false;
}
osmIds.add(osmId);
return true;
});
selectedFeatures.sort((f1: Feature, f2: Feature) => {
const ctx1 = f1.get('context');
const ctx2 = f2.get('context');
if (ctx1.gpxId < ctx2.gpxId) {
return 1;
} else if (ctx1.gpxId > ctx2.gpxId) {
return -1;
}
const level2Key1 = level2Key(f1);
const level2Key2 = level2Key(f2);
if (level2Key1 < level2Key2) {
return -1;
}
if (level2Key1 > level2Key2) {
return 1;
}
if (ctx1.trksegId < ctx2.trksegId) {
return -1;
}
if (ctx1.trksegId > ctx2.trksegId) {
return 1;
}
return 0;
});
selectedFeatures.map((feature: Feature<Geometry>) => {
const gpxId = feature.get('context').gpxId;
if (!hierarchy.hasOwnProperty(gpxId)) {
hierarchy[gpxId] = { type: 'gpx' };
}
const l2key = level2Key(feature);
if (!hierarchy[gpxId].hasOwnProperty(l2key)) {
hierarchy[gpxId][l2key] = {};
if (feature.get('type') === 'trkseg') {
hierarchy[gpxId][l2key].type = 'trk';
} else {
hierarchy[gpxId][l2key].type = feature.get('type');
hierarchy[gpxId][l2key].feature = feature;
}
}
if (feature.get('type') === 'trkseg') {
const trksegId = feature.get('context').trksegId;
if (!hierarchy[gpxId][l2key].hasOwnProperty(trksegId)) {
hierarchy[gpxId][l2key][trksegId] = {
type: 'trkseg',
feature,
};
}
}
});
console.log({
caller: '<Infos/> / clickHandler',
event,
features,
hierarchy,
vectorLayerFeatures,
location: location(),
});
selectedFeatures.map((feature: Feature<Geometry>) => {
const id = feature.get('id');
feature.set('isSelected', true);
// const geometry = feature.getGeometry();
// const length = getLength(geometry, { projection: "EPSG:4326" });
console.log({
caller: '<Infos/> / clickHandler / feature',
event,
feature,
id,
// geometry,
// length,
});
});
setOpen(true);
};
const FeaturesTree: Component<{ featuresHierarchy: any }> = ({
featuresHierarchy,
}) => {
return (
<Tree
title={featuresHierarchy.type || 'voyages'}
content={undefined}
subTree={Object.keys(featuresHierarchy)
.filter((key: string) => key.startsWith('gpx/'))
.map((key: string) => (
<GpxViewer gpxId={key} restrictToHierarchy={featuresHierarchy[key]} />
))}
/>
);
};
const Infos: Component<{}> = (props) => {
const [t, { add, locale, dict }] = useI18n();
const handleClick = () => {
setOpen(false);
};
return (
<Dialog closeHandler={handleClick} open={open()} title={t('nearby')}>
<Stack
spacing={1}
direction='column'
alignItems='center'
sx={{ width: 'calc(100% - 5px)' }}
>
<Tree
title='everything'
content={undefined}
subTree={
<>
<Tree
title={
<>
<div>osm</div>
<OsmFindAll location={location()} />
</>
}
content={undefined}
subTree={
<>
<For each={vectorLayerFeatures}>
{(feature) => (
<Tree
title={
<>
<div>{feature.get('name') || ''}</div>
<div>
<IconButton>
<AddLocationAltIcon />
</IconButton>
<IconButton
onClick={async () => {
await Browser.open({
url: `https://www.qwant.com/?q=${encodeURIComponent(
feature.get('name') || ''
)}&t=web`,
});
}}
>
<TravelExploreIcon />
</IconButton>
</div>
</>
}
content={
<>
<>
{console.log({
caller: 'Infos / vector layer feature',
isHighlighted: isHighlightedTagType(
getTagType(feature)
),
tagValue: getTagType(feature),
properties: feature.getProperties(),
style: style(feature),
})}
</>
<For each={Object.keys(feature.getProperties())}>
{(key: string) => (
<div>
<Switch
fallback={`${key}: ${
feature.getProperties()[key]
}`}
>
<Match when={key === 'website'}>
<Button
size='small'
startIcon={<OpenInNewIcon />}
onClick={async () => {
await Browser.open({
url: feature.getProperties()[key],
});
}}
>
{feature.getProperties()[key]}
</Button>
</Match>
<Match when={key === 'phone'}>
<Button
size='small'
startIcon={<CallIcon />}
href={
'tel:' +
feature.getProperties()[key]
}
>
{feature.getProperties()[key]}
</Button>
</Match>
<Match when={key === 'tags'}>
tags:
<ul>
<For
each={Object.keys(
feature.getProperties()[key]
)}
>
{(tagKey) => (
<li>
{tagKey}:
{
feature.getProperties()[key][
tagKey
]
}
</li>
)}
</For>
</ul>
</Match>
</Switch>
</div>
)}
</For>
</>
}
subTree={undefined}
/>
)}
</For>
</>
}
/>
<FeaturesTree featuresHierarchy={hierarchy} />
</>
}
/>
</Stack>
</Dialog>
);
};
export default Infos;