clean-and-green-philly icon indicating copy to clipboard operation
clean-and-green-philly copied to clipboard

Feature Request: Add basemap toggle between streets tiles and satellite tiles

Open nlebovits opened this issue 1 year ago • 3 comments

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.

nlebovits avatar Sep 10 '24 18:09 nlebovits

I'd like to be assigned this please.

AZBL avatar Oct 02 '24 17:10 AZBL

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 avatar Oct 02 '24 18:10 AZBL

@AZBL yep, good catch. HYBRID and DATAVIZ is what I meant. Thanks for working on this!

nlebovits avatar Oct 02 '24 19:10 nlebovits

This issue has been marked as stale because it has been open for 30 days with no activity.

github-actions[bot] avatar Nov 03 '24 00:11 github-actions[bot]

This came up in our Nov. 14 workshop. I'd love to see someone take this on!

nlebovits avatar Nov 20 '24 01:11 nlebovits

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;

nlebovits avatar Nov 20 '24 14:11 nlebovits

Hey I'd like to tackle this one!

DonovanAndrews300 avatar Nov 24 '24 01:11 DonovanAndrews300

@DonovanAndrews300 assigned!

CodeWritingCow avatar Nov 24 '24 20:11 CodeWritingCow

This issue has been marked as stale because it has been open for 30 days with no activity.

github-actions[bot] avatar Dec 25 '24 00:12 github-actions[bot]

Closed

nlebovits avatar Mar 17 '25 22:03 nlebovits