Skip to content

Commit

Permalink
Merge pull request #853 from stadtnavi/feat/public-pois
Browse files Browse the repository at this point in the history
feat(map-layers): add public poi vector tile layer
  • Loading branch information
hbruch authored Dec 19, 2024
2 parents e4919b6 + a518825 commit aa44f8e
Show file tree
Hide file tree
Showing 26 changed files with 5,736 additions and 125 deletions.
10 changes: 8 additions & 2 deletions app/component/CardHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const CardHeader = (
code,
externalLink,
icon,
dataURI,
icons,
unlinked,
showBackButton, // DT-3472
Expand Down Expand Up @@ -62,12 +63,16 @@ const CardHeader = (
)}
<div className={cx('card-header', className)}>
<div className="card-header-content">
{icon ? (
{icon || dataURI ? (
<div
className="left"
style={{ fontSize: 32, paddingRight: 10, height: 32 }}
>
<Icon img={icon} color={config.colors.primary} />
<Icon
img={icon}
dataURI={dataURI}
color={config.colors.primary}
/>
</div>
) : null}
<div className="card-header-wrapper">
Expand Down Expand Up @@ -122,6 +127,7 @@ CardHeader.propTypes = {
code: PropTypes.string,
externalLink: PropTypes.node,
icon: PropTypes.string,
dataURI: PropTypes.string,
icons: PropTypes.arrayOf(PropTypes.node),
children: PropTypes.node,
unlinked: PropTypes.bool,
Expand Down
2 changes: 1 addition & 1 deletion app/component/Icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Icon.propTypes = {
color: PropTypes.string,
height: PropTypes.number,
id: PropTypes.string,
img: PropTypes.string.isRequired,
img: PropTypes.string,
omitViewBox: PropTypes.bool,
viewBox: PropTypes.string,
width: PropTypes.number,
Expand Down
35 changes: 26 additions & 9 deletions app/component/LayerCategoryDropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const LayerCategoryDropdown = (
const handleCheckAll = settingsChecked => {
onChange(
options
.flatMap(option => option?.categories || option)
.filter(option => option)
.map(option => updateSettings(option.settings, settingsChecked))
.reduce((settings, setting) => {
Expand Down Expand Up @@ -135,22 +136,35 @@ const LayerCategoryDropdown = (
icon="icon-icon_check-white"
showLabel={false}
onChange={e => {
onChange(
updateSettings(option.settings, e.target.checked),
);
if (option.categories) {
option.categories.forEach(category => {
onChange(
updateSettings(category.settings, e.target.checked),
);
});
} else {
onChange(
updateSettings(option.settings, e.target.checked),
);
}
}}
/>
<Icon
className="layer-category-dropdown-header-icon"
dataURI={option.dataURI}
img={option.icon}
viewBox="0 0 15 11"
width={1.875}
height={1.25}
/>
<Message
labelId={option.labelId}
defaultMessage={option.defaultMessage}
/>
{option.labelId || option.defaultMessage ? (
<Message
labelId={option.labelId}
defaultMessage={option.defaultMessage}
/>
) : (
option.label
)}
</div>
{option.checked &&
option.defaultMessage === 'Radnetz Ludwigsburg' ? (
Expand Down Expand Up @@ -185,7 +199,10 @@ const LayerCategoryDropdown = (
<path
d="M0 5 H 20"
stroke="#006400"
style={{ strokeWidth: '2', strokeDasharray: '3' }}
style={{
strokeWidth: '2',
strokeDasharray: '3',
}}
/>
</svg>
</span>
Expand Down Expand Up @@ -226,7 +243,7 @@ const LayerCategoryDropdown = (

LayerCategoryDropdown.propTypes = {
title: PropTypes.string.isRequired,
icon: PropTypes.string.isRequired,
icon: PropTypes.string,
options: PropTypes.array.isRequired,
onChange: PropTypes.func.isRequired,
breakpoint: PropTypes.string.isRequired,
Expand Down
209 changes: 143 additions & 66 deletions app/component/MapLayersDialogContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ class MapLayersDialogContent extends React.Component {
transportMode && transportMode.availableForSelection;
const transportModes = getTransportModes(this.context.config);

const { config } = this.context;
const { config, intl } = this.context;
const datahubLayers =
config.datahubTiles && config.datahubTiles.show
? config.datahubTiles.layers
Expand All @@ -187,6 +187,61 @@ class MapLayersDialogContent extends React.Component {
};
});

const getPoiLayers = layer => {
if (!layer || !layer.categories) {
return [];
}
return layer.categories
.map(({ code, translations, categories, properties }) => {
if (properties && properties.layer.type !== 'poi_layer') {
return null;
}

const { svg } = categories
? categories[0].properties.icon
: properties.icon;

const checked =
categories === undefined
? this.props.mapLayers[code]
: categories.every(
subCategory => this.props.mapLayers[subCategory.code],
);

return {
checked,
label: translations[intl.locale],
key: `map-layer-${code}`,
categories: categories?.map(category => ({
...category,
settings: category.code,
})),
settings: code,
dataURI: svg ? `data:image/svg+xml;base64,${btoa(svg)}` : undefined,
};
})
.filter(Boolean);
};

const layerConfig = config.layers;

const bikeCarLayer = layerConfig?.find(({ code }) => code === 'bike_car');
const sharingServicesLayer = layerConfig?.find(
({ code }) => code === 'sharing_services',
);
const leisureAndTourismLayer = layerConfig?.find(
({ code }) => code === 'leisure_and_tourism',
);
const shoppingAndServicesLayer = layerConfig?.find(
({ code }) => code === 'shopping_and_services',
);
const publicFacilitiesLayer = layerConfig?.find(
({ code }) => code === 'public_facilities',
);
const healthAndSocialServicesLayer = layerConfig?.find(
({ code }) => code === 'health_and_social_services',
);

return (
<>
<button
Expand All @@ -208,11 +263,11 @@ class MapLayersDialogContent extends React.Component {
<div className="map-layers-content">
<div>
<LayerCategoryDropdown
icon="icon-icon_material_rail"
title={this.context.intl.formatMessage({
id: 'map-layer-category-public-transit',
defaultMessage: 'Public Transit',
})}
icon="icon-icon_material_rail"
onChange={this.updateSetting}
options={[
isTransportModeEnabled(transportModes.bus) && {
Expand Down Expand Up @@ -264,11 +319,11 @@ class MapLayersDialogContent extends React.Component {
]}
/>
<LayerCategoryDropdown
icon="icon-icon_bike_car"
title={this.context.intl.formatMessage({
id: 'map-layer-category-bicycle',
defaultMessage: 'Bicycle',
id: 'map-layer-category-bicycle-car',
defaultMessage: 'Bicycle & Car',
})}
icon="icon-icon_material_bike"
onChange={this.updateSetting}
options={[
this.context.config.parkAndRideForBikes &&
Expand All @@ -288,14 +343,59 @@ class MapLayersDialogContent extends React.Component {
this.props.lang,
),
)
.concat(datahubBicycleLayers)}
.concat([
this.context.config.roadworks &&
this.context.config.roadworks.show && {
checked: roadworks,
defaultMessage: 'Roadworks',
labelId: 'map-layer-roadworks',
icon: 'icon-icon_roadworks',
settings: 'roadworks',
},
this.context.config.weatherStations &&
this.context.config.weatherStations.show && {
checked: weatherStations,
defaultMessage: 'Road weather',
labelId: 'map-layer-weather-stations',
icon: 'icon-icon_stop_monitor',
settings: 'weatherStations',
},
this.context.config.parkAndRide &&
this.context.config.parkAndRide.show && {
checked: parkAndRide,
disabled: !!this.props.mapLayerOptions?.parkAndRide
?.isLocked,
defaultMessage: 'Park &amp; ride',
labelId: 'map-layer-park-and-ride',
icon: 'icon-icon_open_carpark',
settings: 'parkAndRide',
},
this.context.config.chargingStations &&
this.context.config.chargingStations.show && {
checked: chargingStations,
defaultMessage: 'Charging stations',
labelId: 'map-layer-charging-stations',
icon: 'icon-icon_stop_car_charging_station',
settings: 'chargingStations',
},
])
.concat(
this.layerOptionsByCategory(
'car',
config.geoJson?.layers,
geoJson,
this.props.lang,
),
)
.concat(datahubBicycleLayers)
.concat(getPoiLayers(bikeCarLayer))}
/>
<LayerCategoryDropdown
icon="icon-icon_material_bike_scooter"
title={this.context.intl.formatMessage({
id: 'map-layer-category-sharing',
defaultMessage: 'Sharing',
})}
icon="icon-icon_material_bike_scooter"
onChange={this.updateSetting}
options={[
this.context.config?.cityBike?.showCityBikes &&
Expand Down Expand Up @@ -341,75 +441,52 @@ class MapLayersDialogContent extends React.Component {
icon: 'icon-icon_carpool_stops',
settings: { stop: 'carpool', terminal: 'carpool' },
},
]}
].concat(getPoiLayers(sharingServicesLayer))}
/>
<LayerCategoryDropdown
icon="icon-icon_leisure_tourism"
title={this.context.intl.formatMessage({
id: 'map-layer-category-car',
defaultMessage: 'Car',
id: 'map-layer-category-leisure-tourism',
defaultMessage: 'Leisure & Tourism',
})}
icon="icon-icon_material_car"
onChange={this.updateSetting}
options={[
this.context.config.parkAndRide &&
this.context.config.parkAndRide.show && {
checked: parkAndRide,
disabled: !!this.props.mapLayerOptions?.parkAndRide
?.isLocked,
defaultMessage: 'Park &amp; ride',
labelId: 'map-layer-park-and-ride',
icon: 'icon-icon_open_carpark',
settings: 'parkAndRide',
},
this.context.config.chargingStations &&
this.context.config.chargingStations.show && {
checked: chargingStations,
defaultMessage: 'Charging stations',
labelId: 'map-layer-charging-stations',
icon: 'icon-icon_stop_car_charging_station',
settings: 'chargingStations',
},
].concat(
this.layerOptionsByCategory(
'car',
config.geoJson?.layers,
geoJson,
this.props.lang,
),
)}
options={[]
.concat(getPoiLayers(leisureAndTourismLayer))
.concat(
this.layerOptionsByCategory(
'other',
config.geoJson?.layers,
geoJson,
this.props.lang,
),
)}
/>
<LayerCategoryDropdown
icon="icon-icon_shopping_services"
title={this.context.intl.formatMessage({
id: 'map-layer-category-others',
defaultMessage: 'Others',
id: 'map-layer-category-shopping-services',
defaultMessage: 'Shopping & Services',
})}
icon="icon-icon_material_map"
onChange={this.updateSetting}
options={[
this.context.config.roadworks &&
this.context.config.roadworks.show && {
checked: roadworks,
defaultMessage: 'Roadworks',
labelId: 'map-layer-roadworks',
icon: 'icon-icon_roadworks',
settings: 'roadworks',
},
this.context.config.weatherStations &&
this.context.config.weatherStations.show && {
checked: weatherStations,
defaultMessage: 'Road weather',
labelId: 'map-layer-weather-stations',
icon: 'icon-icon_stop_monitor',
settings: 'weatherStations',
},
].concat(
this.layerOptionsByCategory(
'other',
config.geoJson?.layers,
geoJson,
this.props.lang,
),
)}
options={getPoiLayers(shoppingAndServicesLayer)}
/>
<LayerCategoryDropdown
icon="icon-icon_public_facilities"
title={this.context.intl.formatMessage({
id: 'map-layer-category-public-facilities',
defaultMessage: 'Public Facilities',
})}
onChange={this.updateSetting}
options={getPoiLayers(publicFacilitiesLayer)}
/>
<LayerCategoryDropdown
icon="icon-icon_health_social_services"
title={this.context.intl.formatMessage({
id: 'map-layer-category-health-social-services',
defaultMessage: 'Health & Social Services',
})}
onChange={this.updateSetting}
options={getPoiLayers(healthAndSocialServicesLayer)}
/>
</div>

Expand Down
Loading

0 comments on commit aa44f8e

Please sign in to comment.