map / src /tileProviders.js
PH70248's picture
Add files using upload-large-folder tool
618aeaa verified
Raw
History Blame Contribute Delete
6.87 kB
const DEFAULT_MAPBOX_STYLE_ID = "mapbox/light-v11";
const DEFAULT_CITY_TILE_STYLES = [
{ id: "light", label: "浅色", styleId: "mapbox/light-v11" },
{ id: "streets", label: "街道", styleId: "mapbox/streets-v12" },
{ id: "outdoors", label: "地形", styleId: "mapbox/outdoors-v12" },
{ id: "satellite", label: "卫星", styleId: "mapbox/satellite-streets-v12" },
{ id: "custom", label: "自定义", styleId: "" },
];
const OSM_PROVIDER = {
name: "osm",
attribution: "© OpenStreetMap",
tileSize: 256,
};
const CARTO_LIGHT_PROVIDER = {
name: "cartoLight",
attribution: "© OpenStreetMap © CARTO",
tileSize: 256,
};
const LOCAL_CITY_TILES_ATTRIBUTION = "© Mapbox © OpenStreetMap";
function normalizeProviderName(name) {
return String(name || "osm").replace(/[-_\s]/g, "").toLowerCase();
}
function normalizeMapboxStyleId(styleId = DEFAULT_MAPBOX_STYLE_ID) {
const cleaned = String(styleId || DEFAULT_MAPBOX_STYLE_ID)
.replace(/^styles\/v1\//, "")
.replace(/^\/+|\/+$/g, "");
const stylePath = cleaned.includes("/") ? cleaned : `mapbox/${cleaned}`;
return stylePath.split("/").map((part) => encodeURIComponent(part)).join("/");
}
function normalizeStyleOption(style) {
const id = String(style?.id || "").trim();
const label = String(style?.label || id).trim();
const styleId = String(style?.styleId || style?.mapboxStyleId || "").trim();
if (!id || !label || (id !== "custom" && !styleId)) return null;
return { id, label, styleId };
}
function normalizeTileBounds(bounds) {
if (!bounds || typeof bounds !== "object") return null;
const normalized = {
z: Number(bounds.z),
minX: Number(bounds.minX),
maxX: Number(bounds.maxX),
minY: Number(bounds.minY),
maxY: Number(bounds.maxY),
};
if (Object.values(normalized).some((value) => !Number.isInteger(value))) return null;
if (normalized.minX > normalized.maxX || normalized.minY > normalized.maxY) return null;
return normalized;
}
function tileIsInsideBounds(bounds, { z, x, y }) {
if (!bounds) return true;
return z === bounds.z
&& x >= bounds.minX
&& x <= bounds.maxX
&& y >= bounds.minY
&& y <= bounds.maxY;
}
export function normalizeCityTileStyles(runtimeConfig = {}) {
const configured = Array.isArray(runtimeConfig.mapboxStyles)
? runtimeConfig.mapboxStyles.map(normalizeStyleOption).filter(Boolean)
: [];
const stylesById = new Map();
for (const style of configured) stylesById.set(style.id, style);
for (const style of DEFAULT_CITY_TILE_STYLES) {
if (!stylesById.has(style.id)) stylesById.set(style.id, style);
}
return Array.from(stylesById.values());
}
function resolveMapboxStyleId(special, runtimeConfig) {
if (special.mapboxStyleId) return special.mapboxStyleId;
const styles = normalizeCityTileStyles(runtimeConfig);
const activeStyleId = special.activeMapStyleId
|| runtimeConfig.activeMapStyleId
|| runtimeConfig.defaultMapStyleId
|| runtimeConfig.defaultMapboxStyleKey
|| runtimeConfig.defaultStyleId
|| "";
if (!activeStyleId) {
return runtimeConfig.mapboxStyleId
|| runtimeConfig.styleId
|| runtimeConfig.mapbox?.styleId
|| styles[0]?.styleId
|| DEFAULT_MAPBOX_STYLE_ID;
}
if (activeStyleId === "custom") {
return runtimeConfig.customMapboxStyleId
|| runtimeConfig.mapboxStyleId
|| runtimeConfig.styleId
|| runtimeConfig.mapbox?.styleId
|| DEFAULT_MAPBOX_STYLE_ID;
}
return styles.find((style) => style.id === activeStyleId)?.styleId
|| runtimeConfig.mapboxStyleId
|| runtimeConfig.styleId
|| runtimeConfig.mapbox?.styleId
|| DEFAULT_MAPBOX_STYLE_ID;
}
export function resolveCityTileProvider(special = {}, runtimeConfig = {}) {
const providerName = normalizeProviderName(
special.tileProvider
|| runtimeConfig.cityTileProvider
|| runtimeConfig.tileProvider
|| runtimeConfig.provider,
);
if (providerName === "mapbox" || providerName === "mapboxstatic" || providerName === "mapboxtiles") {
const token = special.mapboxAccessToken
|| special.mapboxToken
|| runtimeConfig.mapboxAccessToken
|| runtimeConfig.mapboxToken
|| runtimeConfig.mapbox?.accessToken
|| runtimeConfig.mapbox?.token
|| "";
if (!token) return { ...CARTO_LIGHT_PROVIDER, fallbackReason: "missing-mapbox-token" };
return {
name: "mapboxStatic",
attribution: "© Mapbox © OpenStreetMap",
tileSize: Number(special.tileSize || runtimeConfig.tileSize || 256) || 256,
mapboxStyleId: normalizeMapboxStyleId(resolveMapboxStyleId(special, runtimeConfig)),
mapboxAccessToken: token,
retina: special.retinaTiles ?? runtimeConfig.retinaTiles ?? true,
};
}
if (providerName === "carto" || providerName === "cartolight" || providerName === "cartopositron") {
return { ...CARTO_LIGHT_PROVIDER };
}
if (providerName === "local" || providerName === "localcitytiles" || providerName === "localtiles") {
const baseUrl = String(
special.localTileBaseUrl
|| special.tileBaseUrl
|| runtimeConfig.localTileBaseUrl
|| runtimeConfig.localCityTileBaseUrl
|| "",
).replace(/\/+$/g, "");
if (!baseUrl) return { ...CARTO_LIGHT_PROVIDER, fallbackReason: "missing-local-tile-base-url" };
return {
name: "localCityTiles",
attribution: special.localTileAttribution || runtimeConfig.localTileAttribution || LOCAL_CITY_TILES_ATTRIBUTION,
tileSize: Number(special.tileSize || runtimeConfig.tileSize || 256) || 256,
baseUrl,
tileBounds: normalizeTileBounds(special.localTileBounds || runtimeConfig.localTileBounds),
version: String(special.localTileVersion || runtimeConfig.localTileVersion || "").trim(),
};
}
return { ...OSM_PROVIDER };
}
export function buildCityTileUrl(provider, { z, x, y }) {
if (provider?.name === "localCityTiles") {
if (!tileIsInsideBounds(provider.tileBounds, { z, x, y })) return "";
const versionSuffix = provider.version ? `?v=${encodeURIComponent(provider.version)}` : "";
return `${provider.baseUrl}/${z}/${x}/${y}.png${versionSuffix}`;
}
if (provider?.name === "mapboxStatic") {
const scaleSuffix = provider.retina === false ? "" : "@2x";
const params = new URLSearchParams({ access_token: provider.mapboxAccessToken });
return `https://api.mapbox.com/styles/v1/${provider.mapboxStyleId}/tiles/${provider.tileSize}/${z}/${x}/${y}${scaleSuffix}?${params.toString()}`;
}
if (provider?.name === "cartoLight") {
const scaleSuffix = provider.retina === false ? "" : "@2x";
return `https://a.basemaps.cartocdn.com/light_all/${z}/${x}/${y}${scaleSuffix}.png`;
}
return `https://tile.openstreetmap.org/${z}/${x}/${y}.png`;
}
export function runtimeCityTileConfig() {
return globalThis.CITYBOOK_MAP_CONFIG || {};
}