地图叠加层 CadMapOverlay
大约 5 分钟
地图叠加层 CadMapOverlay
CadMapOverlay 用于将 WebCAD 视图叠加到 vjmap/Mapbox GL 地图上,实现 CAD 图纸与地图的融合显示。支持视图同步、实体选择、坐标转换等功能。
特性
- 视图同步:WebCAD 视图自动跟随地图缩放、平移、旋转
- 平滑动画:使用 CSS transform 实现平滑过渡,避免抖动
- 实体选择:支持点击选择实体,Shift+点击追加选择
- 坐标转换:CAD 坐标与经纬度自动转换
- 事件监听:选择变化回调、地图范围更新监听
- 透明背景:WebCAD 背景透明,与地图无缝融合
基本使用
创建地图叠加层
import { CadMapOverlay, Engine, LineEnt, CircleEnt } from 'vjcad';
// 地图范围(CAD 坐标)
const mapExtent = [0, 0, 1000, 1000];
// 创建叠加层
const cadOverlay = new CadMapOverlay({
bounds: mapExtent,
serviceUrl: 'http://127.0.0.1:27660/api/v1',
accessToken: 'your-token',
themeMode: 0, // 0=深色, 1=浅色
enableSelection: true,
onSelectionChanged: (selection) => {
console.log('选中实体:', selection);
}
});
// 添加到 vjmap 地图
await cadOverlay.addTo(map);
// 添加实体
const line = new LineEnt([100, 100], [500, 500]);
line.setDefaults();
line.color = 1;
const circle = new CircleEnt([300, 300], 100);
circle.setDefaults();
circle.color = 3;
cadOverlay.addEntities([line, circle]);
cadOverlay.zoomToExtents();配置选项
CadMapOverlayOptions
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
bounds | number[] | GeoBounds | 必填 | CAD 范围 [minX, minY, maxX, maxY] |
serviceUrl | string | 必填 | WebCAD 服务地址 |
accessToken | string | 必填 | 访问令牌 |
themeMode | number | 0 | 主题模式(0=深色, 1=浅色) |
minZoom | number | 0 | 最小显示级别 |
maxZoom | number | 100 | 最大显示级别 |
enableSelection | boolean | true | 是否允许选择实体 |
smoothAnimation | boolean | true | 是否使用平滑动画模式 |
onSelectionChanged | Function | - | 选择变化回调 |
动画模式
// 平滑动画模式(默认)
// 动画过程中使用 CSS transform,动画结束后重绘
// 优点:无抖动,动画平滑
const overlay1 = new CadMapOverlay({
bounds: mapExtent,
smoothAnimation: true, // 默认值
// ...
});
// 实时重绘模式
// 每次移动都重绘视图
// 优点:响应更及时;缺点:高缩放级别可能有抖动
const overlay2 = new CadMapOverlay({
bounds: mapExtent,
smoothAnimation: false,
// ...
});API 方法
地图操作
// 添加到地图
await cadOverlay.addTo(map);
await cadOverlay.addTo(map, 'container-id'); // 指定父容器
// 从地图移除
cadOverlay.remove();
// 显示/隐藏
cadOverlay.setVisible(true);
cadOverlay.setVisible(false);
// 重绘
cadOverlay.redraw();视图操作
// 缩放到全图
cadOverlay.zoomToExtents();
// 更新 CAD 范围
cadOverlay.updateBounds([0, 0, 2000, 2000]);
// 获取当前范围
const bounds = cadOverlay.getCadBounds();实体操作
// 添加实体
cadOverlay.addEntities([line, circle, text]);
// 获取 MainView 实例(访问底层 API)
const cadView = cadOverlay.getCadView();选择操作
// 获取当前选择
const selection = cadOverlay.getSelection();
// 设置选择
cadOverlay.setSelection([entity1, entity2]);
// 清空选择
cadOverlay.clearSelection();坐标转换
// CAD 坐标转经纬度
const lngLat = cadOverlay.cadToLngLat(500, 500);
// { lng: 116.xxx, lat: 39.xxx }
// 经纬度转 CAD 坐标
const cadPt = cadOverlay.lngLatToCad({ lng: 116.xxx, lat: 39.xxx });
// { x: 500, y: 500 }事件处理
选择变化回调
const cadOverlay = new CadMapOverlay({
// ...
onSelectionChanged: (selection) => {
if (selection.length === 0) {
console.log('选择已清空');
} else {
console.log(`选中 ${selection.length} 个实体:`);
selection.forEach((ent, i) => {
console.log(` [${i + 1}] ${ent.type}, ID: ${ent.id}`);
});
}
}
});监听地图范围更新
当调用 map.updateMapExtent() 时,叠加层会自动更新 CAD 范围:
// vjmap 更新地图范围
map.updateMapExtent([0, 0, 2000, 2000]);
// CadMapOverlay 自动监听 'updateMapExtent' 事件并更新交互操作
| 操作 | 效果 |
|---|---|
| 滚轮上下 | 缩放地图和 CAD 视图 |
| 左键拖动 | 平移地图和 CAD 视图 |
| 左键点击 | 选中 CAD 实体 |
| Shift+点击 | 追加/取消选择实体 |
| ESC | 清空选择 |
| 右键拖动 | 旋转地图(如果地图支持) |
完整示例
与 vjmap 集成
// 动态加载 vjmap
async function loadVjmap() {
// 加载 CSS
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://vjmap.com/demo/js/vjmap/vjmap.min.css';
document.head.appendChild(link);
// 加载 JS
return new Promise((resolve) => {
const script = document.createElement('script');
script.src = 'https://vjmap.com/demo/js/vjmap/vjmap.min.js';
script.onload = resolve;
document.head.appendChild(script);
});
}
await loadVjmap();
// 创建地图
const mapExtent = [0, 0, 1000, 1000];
const prj = new vjmap.GeoProjection(vjmap.GeoBounds.fromArray(mapExtent));
const map = new vjmap.Map({
container: 'map',
style: vjmap.openMapDarkStyle(),
center: prj.toLngLat(vjmap.GeoBounds.fromArray(mapExtent).center()),
zoom: 2,
pitch: 0,
pitchWithRotate: false,
maxPitch: 0,
renderWorldCopies: false,
});
map.setMapProjection(prj);
map.addControl(new vjmap.NavigationControl());
await new Promise(resolve => map.on('load', resolve));
// 创建 WebCAD 叠加层
const { CadMapOverlay, LineEnt, CircleEnt, TextEnt, Engine } = vjcad;
const cadOverlay = new CadMapOverlay({
bounds: mapExtent,
serviceUrl: env.serviceUrl,
accessToken: env.accessToken,
themeMode: 0,
enableSelection: true,
smoothAnimation: true,
onSelectionChanged: (selection) => {
console.log(`选中 ${selection.length} 个实体`);
}
});
await cadOverlay.addTo(map);
// 创建随机实体
function addRandomEntities() {
const bounds = cadOverlay.getCadBounds();
const [minX, minY, maxX, maxY] = bounds;
const entities = [];
// 随机线段
for (let i = 0; i < 10; i++) {
const x1 = minX + Math.random() * (maxX - minX);
const y1 = minY + Math.random() * (maxY - minY);
const x2 = minX + Math.random() * (maxX - minX);
const y2 = minY + Math.random() * (maxY - minY);
const line = new LineEnt([x1, y1], [x2, y2]);
line.setDefaults();
line.color = Math.floor(Math.random() * 7) + 1;
entities.push(line);
}
// 随机圆
for (let i = 0; i < 5; i++) {
const cx = minX + Math.random() * (maxX - minX);
const cy = minY + Math.random() * (maxY - minY);
const radius = (maxX - minX) * 0.05 * (0.5 + Math.random());
const circle = new CircleEnt([cx, cy], radius);
circle.setDefaults();
circle.color = Math.floor(Math.random() * 7) + 1;
entities.push(circle);
}
// 随机文字
const texts = ['WebCAD', 'vjmap', '测试', '示例'];
for (let i = 0; i < 4; i++) {
const x = minX + Math.random() * (maxX - minX);
const y = minY + Math.random() * (maxY - minY);
const text = new TextEnt();
text.insertionPoint = [x, y];
text.text = texts[i];
text.height = (maxX - minX) * 0.03;
text.setDefaults();
text.color = Math.floor(Math.random() * 7) + 1;
entities.push(text);
}
cadOverlay.addEntities(entities);
}
addRandomEntities();
cadOverlay.zoomToExtents();注意事项
坐标系统:CAD 坐标通过 vjmap 的投影系统转换为经纬度,需确保
bounds与map.setMapProjection()使用相同的范围透明背景:WebCAD 层背景透明,可以看到下方的地图瓦片
事件穿透:WebCAD 层的
pointer-events设为none,鼠标事件由地图处理,再通过坐标计算进行实体拾取选择模式:
- 单击选中单个实体
- Shift+单击追加/取消选择
- ESC 清空选择
性能优化:
- 默认使用
smoothAnimation: true,动画更平滑 - 如需实时响应,可设为
false,但高缩放级别可能有轻微抖动
- 默认使用
不支持倾斜:地图
pitch应设为 0,不支持 3D 倾斜视图
下一步
- Viewer 查看模式 - 独立的 CAD 查看器
- 预览视图组件 - 轻量级预览组件
- 事件系统 - 更多事件类型