Select to view content in your preferred language

Basemap Gallery component - Add basemap from tile layer

977
5
Jump to solution
12-19-2025 12:00 PM
MatthewDriscoll
MVP Alum

Does anyone have an example of how to remove the default basemaps in the basemap gallery component and add our own from a service layer.  I am struggling.  Thanks.

Tags (1)
0 Kudos
1 Solution

Accepted Solutions
AnneFitz
Esri Regular Contributor

Hi @MatthewDriscoll - yes you can use the Basemap Gallery component to do this! Just set the source via JavaScript after adding the component to your markup. Example code snippet here - https://developers.arcgis.com/javascript/latest/references/map-components/arcgis-basemap-gallery/#so...

View solution in original post

0 Kudos
5 Replies
Laura
by MVP Regular Contributor
MVP Regular Contributor
0 Kudos
MatthewDriscoll
MVP Alum

No, not through online.  Using the SDK code.  Add the component in HTML and put it in a slot, then customize it in JS.  This the way the new format is supposed to go, no? 

    <!--Basemap Gallery-->
    <arcgis-basemap-gallery
        id="baseMapGal"
        slot="top-right">
    </arcgis-basemap-gallery>
const basemapGallery = document.getElementById("baseMapGal");

 

0 Kudos
MatthewDriscoll
MVP Alum

I think I may have gotten it, or at least a working solution, by using the LocalBasemapsSources?  However the format/look is different.  So I am not sure.  Would still like to know if the actual basemap gallery component is a direction I can take. 

let basemapGallery = new BasemapGallery({
 source: new LocalBasemapsSource({
   basemaps: [
     myBasemap//Basemap.fromId("topo-vector"), // create a basemap from a well known id basemap
   ]
  }),
 view: view
});
view.ui.add(basemapGallery, 'top-right');


 

0 Kudos
AnneFitz
Esri Regular Contributor

Hi @MatthewDriscoll - yes you can use the Basemap Gallery component to do this! Just set the source via JavaScript after adding the component to your markup. Example code snippet here - https://developers.arcgis.com/javascript/latest/references/map-components/arcgis-basemap-gallery/#so...

0 Kudos
kurtia
by
Emerging Contributor

 

This is how I am adding custom basemaps gallery:

import { BASEPATH_URL_PATH } from "@/config/basepath.config";

export const basemapConfigs = {
    // WebTileLayer (XYZ/TMS tiles from mbtiles)
    customtiles: {
        id: 'custom-tiles',
        title: 'Custom Tiles',
        url: 'https://mydomain.com/mbtiles/custom.mbtiles/{z}/{x}/{y}',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/BasemapDefault.png`,
        type: 'custom_webtile', // indicates this is an XYZ/TMS tile layer
        minZoom: 9,
        maxZoom: 18,
    },
    // TileLayer
    default: {
        id: 'default',
        title: 'Basemap2',
        url: 'https://mydomain.com/server/rest/services/Basemap/Basemap/MapServer',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/BasemapDefault.png`,
    },
    // TileLayer
    aerial: {
        id: 'base-aerial',
        title: 'Aerial',
        url: 'https://mydomain.com/server/rest/services/Basemap/BasemapAerial/MapServer',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/BasemapAerial.png`,
    },
    // TileLayer
    grayscale: {
        id: 'grayscale',
        title: 'Grayscale',
        url: 'https://mydomain.com/server/rest/services/Basemap/BasemapGrayscale/MapServer',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/BasemapGrayscale.png`,
    },
    // TileLayer
    topohillshade: {
        id: 'topohillshade',
        title: 'TopoHillShade',
        url: 'https://mydomain.com/server/rest/services/Basemap/TopoHillShade/MapServer',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/TopoHillShade.png`,
    },
};

 

In map store: 

import { basemapConfigs } from "@/config/basemap.configs";
import Basemap from "@arcgis/core/Basemap";
import MapImageLayer from "@arcgis/core/layers/MapImageLayer";
import TileLayer from "@arcgis/core/layers/TileLayer";
import WebTileLayer from "@arcgis/core/layers/WebTileLayer";
import LocalBasemapsSource from "@arcgis/core/widgets/BasemapGallery/support/LocalBasemapsSource";
import { create } from "zustand";
import BaseTileLayer from "@arcgis/core/layers/BaseTileLayer";

/**
 * Helper function to convert zoom level to scale
 * Using Web Mercator scale approximation
 */
const getScaleFromZoom = (zoom) => {
  const earthCircumference = 40075016.686; // meters
  const tileSize = 256;
  return earthCircumference / (tileSize * Math.pow(2, zoom));
};

export const useMapStore = create((set, get) => ({
  mapElement: null,
  basemap: basemapConfigs.default,
  loading: true,
  map: null,
  view: null,
  gallery: null,

  setMapElement: (el) => {
    const gallery = el?.querySelector("arcgis-basemap-gallery");
    const map = document.querySelector("arcgis-map")?.map;
    const view = document.querySelector("arcgis-map")?.view;

    // Configure popup docking
    if (view) {
      view.popup.dockEnabled = true;
      view.popup.dockOptions = {
        buttonEnabled: true,
        breakpoint: false,
        position: "top-left",
      };
    }

    set({
      mapElement: el,
      gallery,
      map,
      view,
    });
  },

  setMapLoaded: (value) => set({ loading: value }),

  initBasemaps: () => {
    const customBasemaps = Object.keys(basemapConfigs).map((key) => {
      const config = basemapConfigs[key];
      const { url, title, type, minZoom, maxZoom } = config;

      let basemapLayer;

      // Define the class to add custom web tiles (mbtiles layer)
      const CustomMeckLayer = BaseTileLayer.createSubclass({
        properties: {
          urlTemplate: null,
        },
        // we need to match URL's structure /z/x/y to level/col/row
        getTileUrl: function (level, row, col) {
          return this.urlTemplate
            .replace("{z}", level)
            .replace("{x}", col)
            .replace("{y}", row);
        },
      });

      if (type === "custom_webtile") {
        basemapLayer = new CustomMeckLayer({
          // Pass the RAW string with placeholders here
          urlTemplate: config.url,
          title: title,
        });
        basemapLayer.minScale = 500000;
        basemapLayer.maxScale = 0;
      } else if (type === "webtile") {
        // WebTileLayer for XYZ/TMS tiles (e.g., mbtiles)
        basemapLayer = new WebTileLayer({
          urlTemplate: url,
          title,
          ...(minZoom !== undefined && { minScale: getScaleFromZoom(minZoom) }),
          ...(maxZoom !== undefined && { maxScale: getScaleFromZoom(maxZoom) }),
        });
      } else if (
        ["vectorbasemap", "vectorbasemapaerial", "vectorbasemapparks"].includes(
          key,
        )
      ) {
        basemapLayer = new MapImageLayer({ url, title });
      } else {
        basemapLayer = new TileLayer({ url, title });
      }
      return new Basemap({
        baseLayers: [basemapLayer],
        title,
        thumbnailUrl: config?.thumbnail,
      });
    });

    // Use gallery from mapElement
    const gallery = get().gallery;
    if (gallery && customBasemaps.length > 0) {
      gallery.source = new LocalBasemapsSource({ basemaps: customBasemaps });
    }
    set({ basemap: customBasemaps[0] });
  },

  initMap: async () => {
    const mapElement = get().mapElement;
    if (!mapElement) return;
    set({ loading: true });
    get().initBasemaps();
    set({
      loading: false, // loading done
    });
  },
}));

 

you can now directly use initMap function in your map component:

export default function MapViewer() {
  const { setMapElement, initMap, basemap } = useMapStore();

  useEffect(() => {
    // We need to wait for <arcgis-map> to be in DOM
    const arcgisMapElem = document.querySelector("arcgis-map");
    if (!arcgisMapElem) return;

    // set ref into zustand store
    setMapElement(arcgisMapElem);

    // initialize basemap gallery and set default basemap
    initMap();
  }, [initMap, setMapElement]);


  return (
    <div className="w-full h-full relative">
      <ArcgisMap
        className={mapConfig.initClass}
        basemap={basemap}
        center={mapConfig.initCenter}
        zoom={mapConfig.initZoom}
      >

        {/** Bottom Aligned Basemap Gallery */}
        <div
          className="fixed left-1/2 bottom-4 w-full transform -translate-x-1/2
                  bg-background/20 backdrop-blur-lg p-3
                  rounded-t-2xl shadow-lg"
        >
          <ArcgisBasemapGallery />
        </div>
      </ArcgisMap>
    </div>
  );
}