Appearance
入门
两个最简单的出图方式:直接使用矢量瓦片服务的样式,或直接使用地图方案的样式地址。示例代码里的 client、container、services、maps 由沙箱提供,拷到自己页面时的替换方法见示例总览。
矢量瓦片服务样式
用 client.maplibre.serviceStyle() 取矢量瓦片服务的样式 JSON,直接作为 MapLibre 地图的样式;transformRequest 负责给发往平台的请求带上 Key。样式里的数据源、字体与图标地址都指向平台,不需要再做其他配置。左上角在每次地图静止后统计视野内渲染出的道路段数。示例视野放在尖沙咀、15 级附近,可以缩小查看:瓦片包含范围内的全部道路,小于约一个像素的短路段在低级别不输出;道路数据量大,10 级以下的瓦片中没有道路(tiles.json 中图层的 minzoom 即为 10)。
需要: 一个矢量瓦片服务(示例用香港道路;公开服务匿名即可访问,受保护服务需在沙箱顶部填写 API Key)。
js
在沙箱中打开/**
* @title 矢量瓦片服务样式
* @description 取香港道路矢量瓦片服务的样式 JSON,直接作为 MapLibre 地图的样式;左上角实时统计视野内的道路段数,缩放平移后自动更新。
* @category 入门
* @service demo/roads
*/
// 出错时给出可理解的提示(服务不存在多半是 demo 服务映射或服务路径有误)
const friendly = (e) => (e && e.status === 404 ? '服务不存在,请检查服务路径' : e && e.message)
try {
// 拷到自己页面时:把 services['demo/roads'] 换成你的矢量瓦片服务路径
const path = services['demo/roads']
// serviceStyle 取回的样式里 source、glyphs 与 sprite 都指向平台,可直接交给地图
const style = await client.maplibre.serviceStyle(path)
const map = new maplibregl.Map({
container,
style,
// 给发往平台的请求带上 Key(匿名访问公开服务时什么也不加)
transformRequest: client.transformRequest,
// 尖沙咀一带。道路数据量大:这个服务在 10 级以下不出瓦片(tiles.json 的 minzoom),低级别不输出小于约一个像素的短路段
center: [114.172, 22.298],
zoom: 15.5,
})
map.addControl(new maplibregl.NavigationControl())
// 切片、图标等资源加载失败时 MapLibre 发 error 事件:转成提示,不影响其余内容显示
map.on('error', (e) => console.warn('地图资源加载失败:', e.error && e.error.message))
// 视野统计面板:每次地图静止(idle)后,数一数当前渲染出来的道路要素
const panel = document.createElement('div')
panel.style.cssText = 'position:absolute;top:8px;left:8px;z-index:2;background:#fff;padding:6px 10px;border-radius:6px;box-shadow:0 1px 4px rgba(0,0,0,.3);font:13px/1.6 sans-serif'
container.appendChild(panel)
const layerIds = style.layers.map((l) => l.id)
let logged = false
map.on('idle', () => {
const features = map.queryRenderedFeatures({ layers: layerIds })
const named = features.filter((f) => f.properties.name).length
panel.textContent = `缩放 ${map.getZoom().toFixed(1)}:视野内道路 ${features.length} 段,其中有名称 ${named} 段`
if (!logged) {
logged = true
console.log('样式图层:', layerIds.join('、'), ';', panel.textContent)
}
})
} catch (e) {
console.error(friendly(e))
}地图方案样式
在地图编辑器里制作并发布的地图方案有一个公开的样式地址(client.maplibre.mapStyleUrl()),直接交给 style 即可;方案里引用的服务请求仍然通过 transformRequest 带 Key。地图加载后,示例按数据源把方案的图层分组,左上角的复选框可以分别开关土地利用、水体、建筑、道路与兴趣点。
需要: 一个已发布、可公开访问的地图方案。
js
在沙箱中打开/**
* @title 地图方案样式
* @description 把地图方案公开的样式地址直接交给 style,得到在地图编辑器里配好的香港底图;右上角的复选框按数据源开关方案里的图层。
* @category 入门
* @map demo/map
*/
// 出错时给出可理解的提示(地图方案不存在多半是 demo 映射或方案 id 有误)
const friendly = (e) => (e && e.status === 404 ? '地图方案不存在,请检查方案 id' : e && e.message)
try {
// 拷到自己页面时:把 maps['demo/map'] 换成你的地图方案 id(方案须已发布并公开)
const mapId = maps['demo/map']
const map = new maplibregl.Map({
container,
style: client.maplibre.mapStyleUrl(mapId),
// 方案引用的服务请求仍经 transformRequest 带 Key
transformRequest: client.transformRequest,
// 尖沙咀一带,放大到能看清建筑与兴趣点
center: [114.172, 22.298],
zoom: 15.5,
})
map.addControl(new maplibregl.NavigationControl())
map.on('error', (e) => console.error('地图出错:', e.error && e.error.message))
await new Promise((resolve) => map.once('load', resolve))
// 方案的图层按 source 分组:同一个数据源(服务)下的图层一起开关
const groups = {}
for (const layer of map.getStyle().layers) {
if (!layer.source) continue
groups[layer.source] = [...(groups[layer.source] || []), layer.id]
}
const panel = document.createElement('div')
panel.style.cssText = 'position:absolute;top:8px;left:8px;z-index:2;background:#fff;padding:6px 10px;border-radius:6px;box-shadow:0 1px 4px rgba(0,0,0,.3);font:13px/1.8 sans-serif'
for (const [source, ids] of Object.entries(groups)) {
const label = document.createElement('label')
label.style.display = 'block'
const box = document.createElement('input')
box.type = 'checkbox'
box.checked = true
// setLayoutProperty 改 visibility 只影响显示,不会重新请求样式
box.onchange = () => ids.forEach((id) => map.setLayoutProperty(id, 'visibility', box.checked ? 'visible' : 'none'))
label.append(box, ` ${source}(${ids.length} 个图层)`)
panel.appendChild(label)
}
container.appendChild(panel)
console.log('地图方案加载完成:', Object.entries(groups).map(([s, ids]) => `${s} ${ids.length} 层`).join(','))
} catch (e) {
console.error(friendly(e))
}