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.
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/#source
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> ); }
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');
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");
Is this what you're referring to?
https://www.esri.com/arcgis-blog/products/arcgis-online/mapping/custom-basemap-gallery
Angemeldete Mitglieder können Beiträge verfassen, Updates folgen und mehr. Neu hier? Registriere ein kostenloses Konto.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.