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
Membros conectados podem postar, seguir atualizações e mais. Novo aqui? Registre uma conta gratuita.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.