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.
Solved! Go to Solution.
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...
Is this what you're referring to?
https://www.esri.com/arcgis-blog/products/arcgis-online/mapping/custom-basemap-gallery
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");
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');
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...
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>
);
}