Feature Request: Add basemap toggle between streets tiles and satellite tiles
Is your feature request related to a problem? Please describe. When exploring individual properties on the map, I often like to see the satellite view in Google to understand what the property and its surroundings look like. Currently, I can only see the grey street tiles from Maptiler, so I have to open Google Maps separately to do this.
Describe the solution you'd like Add a style switcher control from Maptiler to allow toggling between the "STREETS" and "HYBRID" basemaps. Make the "STREETS" tiles the default.
I'd like to be assigned this please.
Also @nlebovits I was taking a look at this already. I see you mentioned being able to switch between STREETS and HYBRID and making streets the default. Currently, DATAVIZ is the default. Do you want to make it so you can switch between dataviz and hybrid?
https://docs.maptiler.com/sdk-js/examples/change-map-styles/
@AZBL yep, good catch. HYBRID and DATAVIZ is what I meant. Thanks for working on this!
This issue has been marked as stale because it has been open for 30 days with no activity.
This came up in our Nov. 14 workshop. I'd love to see someone take this on!
From claudi.ai:
// New style switcher control component
const StyleSwitcherControl = ({
map,
position = 'bottom-left',
}: {
map: MaplibreMap | null;
position?: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right';
}) => {
const [activeStyle, setActiveStyle] = useState('streets');
const styles = [
{
id: 'streets',
name: 'Streets',
url: `https://api.maptiler.com/maps/streets/style.json?key=${maptilerApiKey}`,
icon: <MapIcon size={24} />,
},
{
id: 'hybrid',
name: 'Hybrid',
url: `https://api.maptiler.com/maps/hybrid/style.json?key=${maptilerApiKey}`,
icon: <Satellite size={24} />,
},
];
const changeStyle = (styleId: string) => {
if (map) {
const selectedStyle = styles.find(s => s.id === styleId);
if (selectedStyle) {
map.setStyle(selectedStyle.url);
setActiveStyle(styleId);
}
}
};
return (
<div
className="maplibregl-ctrl maplibregl-ctrl-group absolute z-10"
style={{
bottom: position.includes('bottom') ? '10px' : 'auto',
top: position.includes('top') ? '10px' : 'auto',
left: position.includes('left') ? '10px' : 'auto',
right: position.includes('right') ? '10px' : 'auto'
}}
>
{styles.map((style) => (
<button
key={style.id}
onClick={() => changeStyle(style.id)}
className={`p-2 m-1 rounded-md ${
activeStyle === style.id
? 'bg-blue-500 text-white'
: 'bg-white text-gray-700 hover:bg-gray-100'
}`}
title={style.name}
>
{style.icon}
</button>
))}
</div>
);
};
const MapControls = ({ map }: { map: MaplibreMap | null }) => {
const [smallScreenToggle, setSmallScreenToggle] = useState<boolean>(false);
return (
<>
<NavigationControl showCompass={false} position="bottom-right" />
<GeolocateControl position="bottom-right" />
<ScaleControl />
<StyleSwitcherControl map={map} position="bottom-left" />
{smallScreenToggle || window.innerWidth > 640 ? (
<MapLegendControl
position="bottom-left"
setSmallScreenToggle={setSmallScreenToggle}
layerStyle={layerStylePolygon}
/>
) : (
<div className="custom-legend-info-div maplibregl-ctrl maplibregl-ctrl-group w-[40px] h-[40px]">
<ThemeButton
className="custom-legend-info z-10"
startContent={
<span className="custom-legend-info-icon maplibregl-ctrl-icon"></span>
}
onPress={() => setSmallScreenToggle((s) => !s)}
/>
</div>
)}
</>
);
};
const PropertyMap: FC<PropertyMapProps> = ({
// ... (previous props remain the same)
}) => {
// ... (previous state and effects remain the same)
// map load
return (
<div className="customized-map relative max-sm:min-h-[calc(100svh-100px)] max-sm:max-h-[calc(100svh-100px) h-full overflow-auto w-full">
<Map
mapLib={maplibregl as any}
initialViewState={initialViewState}
mapStyle={`https://api.maptiler.com/maps/dataviz/style.json?key=${maptilerApiKey}`}
onMouseEnter={(e) => changeCursor(e, 'pointer')}
onMouseLeave={(e) => changeCursor(e, 'default')}
onClick={onMapClick}
minZoom={MIN_MAP_ZOOM}
maxZoom={MAX_MAP_ZOOM}
interactiveLayerIds={layers}
onError={(e) => {
setHasLoadingError(true);
}}
onLoad={(e) => {
setMap(e.target);
}}
onSourceData={(e) => {
handleSetFeatures(e);
}}
onMoveEnd={handleSetFeatures}
>
<MapControls map={map} />
{/* ... (rest of the existing component remains the same) */}
</Map>
</div>
);
};
export default PropertyMap;
Hey I'd like to tackle this one!
@DonovanAndrews300 assigned!
This issue has been marked as stale because it has been open for 30 days with no activity.
Closed