主题
地图 Map
createMap 工厂函数和 MapModel 类是标准版 API 的入口,负责地图的创建、配置和生命周期管理。
createMap(工厂函数)
异步工厂函数,创建地图并在返回前完成引擎延迟加载与首帧就绪。
ts
async function createMap(options: MapOptions): Promise<MapModel>;MapOptions 接口
ts
interface MapOptions {
target: string | HTMLElement; // 地图容器 ID 或 DOM 元素
engine: EngineId; // 引擎标识:'ol' | 'maplibre' | 'cesium'
center?: Coordinate; // 初始中心 [经度, 纬度]
zoom?: number; // 初始缩放级别
bearing?: number; // 初始方位角(度)
pitch?: number; // 初始俯仰角(度)
basemap?: string; // 底图标识
style?: string | StyleSpec; // 地图样式
maxZoom?: number; // 最大缩放
minZoom?: number; // 最小缩放
bounds?: Extent; // 初始视图范围
controls?: ControlOptions[]; // 初始控件
layers?: LayerOptions[]; // 初始图层
sources?: SourceOptions[]; // 初始数据源
// ... 更多选项
}示例
ts
import { createMap } from '@gmap/standard';
// 基本创建
const map = await createMap({
target: 'map-container',
engine: 'ol',
center: [116.397, 39.908],
zoom: 12,
});
// 使用 MapLibre 引擎
const map2 = await createMap({
target: 'map2',
engine: 'maplibre',
style: 'https://demotiles.maplibre.org/style.json',
});
// 使用 Cesium 引擎(3D)
const map3 = await createMap({
target: 'map3',
engine: 'cesium',
center: [116.397, 39.908],
zoom: 15,
pitch: 45,
});MapModel
地图模型,管理地图的所有状态和操作。由 createMap 返回,也可直接实例化。
属性
| 属性 | 类型 | 说明 |
|---|---|---|
engine | EngineId | 当前引擎标识 |
ready | boolean | 是否就绪 |
视图控制方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
setCenter(center) | center: Coordinate | this | 设置中心点 |
getCenter() | — | Coordinate | 获取中心点 |
setZoom(zoom) | zoom: number | this | 设置缩放级别 |
getZoom() | — | number | 获取缩放级别 |
zoomIn() | — | this | 放大一级 |
zoomOut() | — | this | 缩小一级 |
setBearing(bearing) | bearing: number | this | 设置方位角 |
getBearing() | — | number | 获取方位角 |
setPitch(pitch) | pitch: number | this | 设置俯仰角 |
getPitch() | — | number | 获取俯仰角 |
setView(options) | options: { center?, zoom?, bearing?, pitch? } | this | 设置完整视图 |
getView() | — | ViewState | 获取当前视图状态 |
fitBounds(extent, options?) | extent: Extent, options?: object | this | 适配到指定范围 |
flyTo(options) | options: { center, zoom?, duration?, ... } | this | 飞行动画到目标位置 |
ts
interface ViewState {
center: Coordinate;
zoom: number;
bearing: number;
pitch: number;
}示例
ts
// 基本视图控制
map.setCenter([117.0, 40.0]);
map.setZoom(14);
// 动态获取
const center = map.getCenter();
const zoom = map.getZoom();
console.log(`当前视图: ${center}, zoom=${zoom}`);
// 适配到范围
map.fitBounds([116.0, 39.0, 117.0, 40.0], { padding: 50 });
// 飞行到目标
map.flyTo({
center: [121.473, 31.230],
zoom: 15,
bearing: 30,
pitch: 60,
duration: 2000,
});
// 完整视图设置
map.setView({
center: [116.397, 39.908],
zoom: 12,
bearing: 0,
pitch: 45,
});
const view = map.getView();图层管理方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
addLayer(layer, beforeId?) | layer: Layer, beforeId?: string | this | 添加图层 |
removeLayer(id) | id: string | this | 移除图层 |
getLayer(id) | id: string | Layer | undefined | 获取图层 |
getLayers() | — | Layer[] | 获取所有图层 |
moveLayer(id, beforeId) | id: string, beforeId: string | this | 移动图层顺序 |
示例
ts
import { TileLayer, FeatureLayer, RasterTileSource, GeoJsonSource, SimpleRenderer, FillSymbol } from '@gmap/standard';
// 添加栅格瓦片图层
const osmSource = new RasterTileSource({
url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
});
const osmLayer = new TileLayer({ id: 'osm', source: osmSource });
map.addLayer(osmLayer);
// 添加要素图层
const data = new GeoJsonSource({ id: 'districts', data: districtsGeoJSON });
const featureLayer = new FeatureLayer({
id: 'districts',
source: data,
renderer: new SimpleRenderer({
symbol: new FillSymbol({ color: '#3388ff', opacity: 0.5 }),
}),
});
map.addLayer(featureLayer, 'osm'); // 在 osm 图层下方插入
// 获取图层
const layer = map.getLayer('districts');
const allLayers = map.getLayers();
console.log(`共 ${allLayers.length} 个图层`);
// 移动图层
map.moveLayer('districts', 'osm');
// 移除图层
map.removeLayer('districts');数据源管理方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
addSource(source) | source: Source | this | 添加数据源 |
getSource(id) | id: string | Source | undefined | 获取数据源 |
removeSource(id) | id: string | this | 移除数据源 |
示例
ts
import { RasterTileSource, GeoJsonSource } from '@gmap/standard';
const source = new RasterTileSource({
id: 'my-tiles',
url: 'https://server/{z}/{x}/{y}.png',
});
map.addSource(source);
const retrieved = map.getSource('my-tiles');
map.removeSource('my-tiles');底图与样式方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
setBasemap(basemap) | basemap: string | this | 切换底图 |
setStyle(style) | style: string | StyleSpec | this | 设置地图样式 |
getStyle() | — | StyleSpec | 获取当前样式 |
示例
ts
// 切换底图
map.setBasemap('satellite');
// 设置样式
map.setStyle({
version: 8,
sources: {
'my-source': { type: 'geojson', data: myGeoJSON },
},
layers: [
{ id: 'my-layer', type: 'fill', source: 'my-source' },
],
});
const style = map.getStyle();控件管理方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
addControl(control) | control: Control | this | 添加控件 |
removeControl(id) | id: string | this | 移除控件 |
示例
ts
import { ZoomControl, ScaleBarControl, Legend } from '@gmap/standard';
map.addControl(new ZoomControl({ position: 'top-left' }));
map.addControl(new ScaleBarControl({ position: 'bottom-left' }));
map.addControl(new Legend({ position: 'bottom-right' }));
map.removeControl('ctrl-xxx');交互管理方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
addInteraction(interaction) | interaction: Interaction | this | 添加交互 |
removeInteraction(id) | id: string | this | 移除交互 |
查询与选取方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
pick(pixel, options?) | pixel: Pixel, options?: object | PickResult | null | 像素拾取 |
boxSelect(bounds) | bounds: Extent | Feature[] | 框选要素 |
ts
interface PickResult {
feature: Feature;
layer: Layer;
coordinate: Coordinate;
distance: number;
}示例
ts
// 像素拾取
map.on('click', (e) => {
const result = map.pick(e.pixel);
if (result) {
console.log('拾取到要素:', result.feature);
console.log('所在图层:', result.layer.id);
console.log('点击坐标:', result.coordinate);
}
});
// 框选
const selected = map.boxSelect([116.3, 39.9, 116.5, 40.0]);
console.log(`选中 ${selected.length} 个要素`);事件方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
on(type, handler) | type: string, handler: Function | this | 绑定事件 |
once(type, handler) | type: string, handler: Function | this | 绑定一次性事件 |
off(type, handler?) | type: string, handler?: Function | this | 解绑事件 |
emit(type, data?) | type: string, data?: unknown | this | 触发自定义事件 |
事件列表
| 事件 | 回调参数 | 说明 |
|---|---|---|
'click' | { pixel, coordinate, feature? } | 单击 |
'dblclick' | { pixel, coordinate, feature? } | 双击 |
'contextmenu' | { pixel, coordinate } | 右键 |
'mousemove' | { pixel, coordinate } | 鼠标移动 |
'mouseenter' | { pixel, coordinate, feature? } | 鼠标进入要素 |
'mouseleave' | { pixel, coordinate, feature? } | 鼠标离开要素 |
'movestart' | — | 视图开始移动 |
'moveend' | — | 视图移动结束 |
'zoomstart' | — | 缩放开始 |
'zoomend' | — | 缩放结束 |
'resize' | { width, height } | 地图容器尺寸变化 |
'load' | — | 地图加载完成 |
'error' | { message, error } | 错误 |
示例
ts
// 监听点击
map.on('click', (e) => {
console.log('点击坐标:', e.coordinate);
if (e.feature) {
console.log('点击要素:', e.feature.properties);
}
});
// 监听移动结束
map.once('moveend', () => {
console.log('视图移动完成');
const center = map.getCenter();
console.log('当前中心:', center);
});
// 自定义事件
map.on('data-loaded', (e) => {
console.log('自定义事件:', e);
});
map.emit('data-loaded', { source: 'my-source' });
// 解绑事件
const handler = (e) => console.log(e);
map.on('click', handler);
map.off('click', handler);工具方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
whenReady() | — | Promise<void> | 等待地图就绪 |
resize() | — | this | 手动触发尺寸更新 |
exportImage(options?) | options?: object | Promise<string> | 导出地图为图片(DataURL) |
getStats() | — | object | 获取地图统计信息 |
destroy() | — | void | 销毁地图,释放资源 |
示例
ts
// 等待就绪
await map.whenReady();
console.log('地图已就绪');
// 导出图片
const imageData = await map.exportImage({
width: 1920,
height: 1080,
format: 'png',
});
// imageData 是 base64 DataURL
// 获取统计
const stats = map.getStats();
console.log(stats);
// { layers: 5, sources: 3, features: 1234, ... }
// 销毁
map.destroy();引擎切换方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
switchEngine(engine) | engine: EngineId | Promise<void> | 切换渲染引擎 |
ts
interface SwitchEngineOptions {
engine: EngineId;
preserveState?: boolean;
}示例
ts
// 从 2D 切换到 3D
await map.switchEngine('cesium');二三维共存
map.enterCoexistence(engineId, options)
进入二三维共存模式,创建辅助引擎与当前引擎并存。
engineId— 辅助引擎 ID(如'cesium'、'openlayers'、'maplibre')options—CoexistenceOptions配置
typescript
const coex = await map.enterCoexistence('cesium', {
mode: 'over-map', // 'over-map' | 'side-by-side'
cameraSync: true, // 自动同步相机
pauseInteractions: true, // 暂停主引擎交互
});map.exitCoexistence()
退出共存模式,销毁辅助引擎。
typescript
map.exitCoexistence();map.toggle3D()
切换辅助引擎的显示/隐藏。
typescript
map.toggle3D();
const coex = map.getCoexistence();
console.log(coex?.isEnabled()); // true or falsemap.getCoexistence()
获取共存管理器实例(如果处于共存模式)。
typescript
const coex = map.getCoexistence();
if (coex) {
coex.setMode('side-by-side');
coex.on('toggle', ({ enabled }) => { ... });
}CoexistenceOptions
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| mode | 'over-map' | 'side-by-side' | — | 共存模式 |
| targetSecondary | string | HTMLElement | — | side-by-side 模式的容器 |
| cameraSync | boolean | true | 是否自动同步相机 |
| syncDirection | 'primary-to-secondary' | 'secondary-to-primary' | 'bidirectional' | 'bidirectional' | 同步方向 |
| pauseInteractions | boolean | true | 是否暂停主引擎交互 |
| refreshPrimaryAfterMoveEndOnly | boolean | false | 只在相机停止后同步主引擎 |
CoexistenceManager
| 方法 | 说明 |
|---|---|
toggle() | 切换辅助引擎启用/禁用 |
enable() | 启用辅助引擎 |
disable() | 禁用辅助引擎 |
setMode(mode) | 切换共存模式 |
getState() | 获取当前状态 |
isEnabled() | 是否已启用 |
getPrimaryAdapter() | 获取主引擎适配器 |
getSecondaryAdapter() | 获取辅助引擎适配器 |
on(type, handler) | 监听事件(toggle、mode-change) |
off(type, handler?) | 移除监听 |
destroy() | 销毁所有资源 |
完整示例
ts
import {
createMap,
TileLayer, FeatureLayer, GraphicsLayer,
RasterTileSource, GeoJsonSource,
SimpleRenderer, FillSymbol, LineSymbol,
ZoomControl, ScaleBarControl, Legend, SearchControl,
DrawInteraction, MeasureInteraction,
Popup,
Style,
} from '@gmap/standard';
// 1. 创建地图
const map = await createMap({
target: 'map',
engine: 'ol',
center: [116.397, 39.908],
zoom: 12,
});
// 2. 添加底图
const osmSource = new RasterTileSource({
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c'],
});
map.addLayer(new TileLayer({ id: 'osm', source: osmSource }));
// 3. 添加数据图层
const data = new GeoJsonSource({
id: 'districts',
data: districtsGeoJSON,
cluster: true,
clusterRadius: 50,
});
const layer = new FeatureLayer({
id: 'districts',
source: data,
renderer: new SimpleRenderer({
symbol: new FillSymbol({ color: '#3388ff', opacity: 0.6 }),
}),
});
map.addLayer(layer);
// 4. 添加控件
map.addControl(new ZoomControl({ position: 'top-left' }));
map.addControl(new ScaleBarControl({ position: 'bottom-left' }));
map.addControl(new Legend({ position: 'bottom-right', layer }));
map.addControl(new SearchControl({
position: 'top-center',
onSelect: (result) => map.flyTo({ center: result.location, zoom: 15 }),
}));
// 5. 添加绘制交互
const draw = new DrawInteraction({ mode: 'polygon' });
map.addInteraction(draw);
draw.on('drawend', (e) => console.log('绘制完成:', e.feature));
// 6. 添加量算交互
const measure = new MeasureInteraction({ mode: 'distance' });
map.addInteraction(measure);
// 7. 事件监听
map.on('click', (e) => {
const result = map.pick(e.pixel);
if (result) {
new Popup()
.setPosition(result.coordinate)
.setContent(`<strong>${result.feature.properties.name}</strong>`)
.open();
}
});
// 8. 视图操作
map.flyTo({ center: [121.473, 31.230], zoom: 15, duration: 2000 });
// 9. 导出
const image = await map.exportImage();
// 10. 清理
// map.destroy();MapModel 与核心类型
| 类型 | 来源 | 说明 |
|---|---|---|
MapModel | @gmap/core | 地图模型 |
Layer | @gmap/core | 图层基类 |
Source | @gmap/core | 数据源基类 |
Feature | @gmap/core | 要素 |
EngineRegistry | @gmap/core | 引擎注册表 |
MockAdapter | @gmap/core | 模拟适配器(测试用) |
ViewSync | @gmap/core | 多视图同步 |
Coordinate | @gmap/core | [lng, lat] 或 [lng, lat, alt] |
Pixel | @gmap/core | [x, y] |
Extent | @gmap/core | [west, south, east, north] |
ViewState | @gmap/core | 视图状态 |
PickResult | @gmap/core | 拾取结果 |
EngineId | @gmap/core | 'ol' | 'maplibre' | 'cesium' |