唯杰地图 logo唯杰地图
VJMAP
EN

地图叠加模式

vjcad/references/quickref/map-overlay.md 8.6 KB337 行
原文

将 WebCAD 叠加到 vjmap 地图上,实现 CAD 与 GIS 的融合显示。

概念

CadMapOverlay 是一个轻量级的 CAD 叠加层,可以添加到 vjmap 地图上,支持:

  • 在地图上显示 CAD 实体
  • 实体选择和交互
  • 视图同步(拖动/缩放/旋转)
  • 独立的坐标系管理

基本用法

初始化 vjmap 地图

// 动态加载 vjmap(如果尚未加载)
const loadVjmap = () => {
    return new Promise((resolve, reject) => {
        if (window.vjmap) {
            resolve(window.vjmap);
            return;
        }
        
        const link = document.createElement('link');
        link.rel = 'stylesheet';
        link.href = 'https://vjmap.com/demo/js/vjmap/vjmap.min.css';
        document.head.appendChild(link);
        
        const script = document.createElement('script');
        script.src = 'https://vjmap.com/demo/js/vjmap/vjmap.min.js';
        script.onload = () => resolve(window.vjmap);
        script.onerror = () => reject(new Error('vjmap 加载失败'));
        document.head.appendChild(script);
    });
};

const vjmap = await loadVjmap();

// 创建 vjmap 服务
const svc = new vjmap.Service(env.serviceUrl, env.accessToken);

// 打开地图
const res = await svc.openMap({
    mapid: 'sys_zp',
    mapopenway: vjmap.MapOpenWay.GeomRender,
    style: vjmap.openMapDarkStyle()
});

const mapExtent = vjmap.GeoBounds.fromString(res.bounds);
const prj = new vjmap.GeoProjection(mapExtent);

// 创建地图实例
const map = new vjmap.Map({
    container: 'map',
    style: svc.vectorStyle(),
    center: prj.toLngLat(mapExtent.center()),
    zoom: 1,
    pitch: 0,
    renderWorldCopies: false
});

map.attach(svc, prj);
await map.onLoad();

添加 CadMapOverlay

const { CadMapOverlay, LineEnt, CircleEnt, TextEnt } = vjcad;

// 创建 CAD 叠加层
const cadOverlay = new CadMapOverlay({
    bounds: mapExtent,              // 地图范围
    serviceUrl: env.serviceUrl,     // 服务地址
    accessToken: env.accessToken,   // 访问令牌
    themeMode: 0,                   // 主题:0=深色, 1=浅色
    enableSelection: true,          // 启用选择
    smoothAnimation: true,          // 平滑动画
    onSelectionChanged: (selection) => {
        if (selection.length === 0) {
            console.log("选择已清空");
        } else {
            console.log(`选中 ${selection.length} 个实体`);
            selection.forEach((ent, i) => {
                console.log(`  [${i + 1}] ${ent.type}`);
            });
        }
    }
});

// 添加到地图
await cadOverlay.addTo(map);

添加实体

const { LineEnt, CircleEnt, TextEnt } = vjcad;

// 获取 CAD 坐标范围
const bounds = cadOverlay.getCadBounds();
const [minX, minY, maxX, maxY] = bounds;

// 创建实体
const entities = [];

// 直线
const line = new LineEnt([minX + 100, minY + 100], [maxX - 100, maxY - 100]);
line.setDefaults();
line.color = 1;
entities.push(line);

// 圆
const centerX = (minX + maxX) / 2;
const centerY = (minY + maxY) / 2;
const circle = new CircleEnt([centerX, centerY], 50);
circle.setDefaults();
circle.color = 3;
entities.push(circle);

// 文字
const text = new TextEnt();
text.insertionPoint = [centerX, centerY + 100];
text.text = "WebCAD";
text.height = 20;
text.setDefaults();
text.color = 5;
entities.push(text);

// 批量添加实体
cadOverlay.addEntities(entities);

视图控制

// 地图 fitBounds 到叠加层的 CAD 范围(构造参数 bounds / updateBounds 设的范围,不是实体实际范围)
cadOverlay.zoomToExtents();

// 显示/隐藏叠加层
cadOverlay.setVisible(true);   // 显示
cadOverlay.setVisible(false);  // 隐藏

// 获取 CAD 坐标范围
const bounds = cadOverlay.getCadBounds();
// 返回: [minX, minY, maxX, maxY]

选择操作

// 启用/禁用选择
cadOverlay.enableSelection = true;
cadOverlay.enableSelection = false;

// 清除选择
cadOverlay.clearSelection();

// 监听选择变化(构造函数中配置)
const cadOverlay = new CadMapOverlay({
    // ...
    onSelectionChanged: (selection) => {
        console.log(`选中 ${selection.length} 个实体`);
    }
});

获取内部 MainView

// 获取内部的 MainView 实例
const cadView = cadOverlay.getCadView();

// Engine 是全局单例——切换到该实例先显式绑定,再使用完整 WebCAD API
Engine.bindViewCache(cadView);
Engine.zoomExtents();

配置选项

选项 类型 说明
bounds GeoBounds 地图范围(必需)
serviceUrl string 后端服务地址
accessToken string 访问令牌
themeMode number 主题:0=深色, 1=浅色
enableSelection boolean 是否启用选择(默认 true)
smoothAnimation boolean 是否启用平滑动画(默认 true)
onSelectionChanged function 选择变化回调
minZoom / maxZoom number 地图级别在 [minZoom, maxZoom) 内才显示叠加层(默认 0 / 100)
themeColors object UI / 对话框主题色(部分覆盖)

smoothAnimation 说明

值 行为
true 使用 CSS transform 平滑过渡,动画结束后重绘
false 实时重绘模式,响应更及时但可能有抖动

API 参考

CadMapOverlay

方法 说明
addTo(map) 添加到 vjmap 地图
getCadView() 获取内部 MainView 实例
addEntities(entities) 添加实体数组
getCadBounds() 获取 CAD 坐标范围
updateBounds(bounds) 更新 CAD 范围并重新对齐
zoomToExtents() 地图 fitBounds 到 CAD 范围(bounds,非实体范围)
setVisible(visible, isDisplay?) 设置可见性(isDisplay=true 用 CSS display,否则增删 DOM)
clearSelection() 清除选择
getSelection() / setSelection(entities) 读取 / 设置选择集
cadToLngLat(x, y) / lngLatToCad(lngLat) CAD 坐标 ↔ 经纬度(借 vjmap 地图投影)
redraw() 重绘叠加层
remove() 移除叠加层并解绑地图事件

属性

属性 类型 说明
enableSelection boolean 是否启用选择

完整示例

const { 
    CadMapOverlay, 
    LineEnt, CircleEnt, TextEnt,
    CadEventManager, CadEvents,
    message 
} = vjcad;

// === 1. 初始化 vjmap ===
const vjmap = await loadVjmap();

const svc = new vjmap.Service(env.serviceUrl, env.accessToken);
const res = await svc.openMap({
    mapid: 'sys_zp',
    mapopenway: vjmap.MapOpenWay.GeomRender,
    style: vjmap.openMapDarkStyle()
});

const mapExtent = vjmap.GeoBounds.fromString(res.bounds);
const prj = new vjmap.GeoProjection(mapExtent);

const map = new vjmap.Map({
    container: 'map',
    style: svc.vectorStyle(),
    center: prj.toLngLat(mapExtent.center()),
    zoom: 1
});

map.attach(svc, prj);
await map.onLoad();

// === 2. 创建 CAD 叠加层 ===
const cadOverlay = new CadMapOverlay({
    bounds: mapExtent,
    serviceUrl: env.serviceUrl,
    accessToken: env.accessToken,
    themeMode: 0,
    enableSelection: true,
    onSelectionChanged: (selection) => {
        message.info(`选中 ${selection.length} 个实体`);
    }
});

await cadOverlay.addTo(map);

// === 3. 添加实体 ===
const bounds = cadOverlay.getCadBounds();
const [minX, minY, maxX, maxY] = bounds;
const avgSize = Math.min(maxX - minX, maxY - minY) / 20;

const entities = [];

// 随机创建 10 个实体
for (let i = 0; i < 5; 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 circle = new CircleEnt([cx, cy], avgSize * (0.5 + Math.random()));
    circle.setDefaults();
    circle.color = Math.floor(Math.random() * 7) + 1;
    entities.push(circle);
}

cadOverlay.addEntities(entities);
cadOverlay.zoomToExtents();

// === 4. 交互控制 ===
// 点击实体可选中
// ESC 取消选择
// 拖动/缩放/旋转地图,CAD 视图同步

使用场景

  • GIS + CAD 融合:在地图上叠加 CAD 图形
  • 设备标注:在地理位置上标注设备信息
  • 管线叠加:将 CAD 管线图叠加到地图上
  • 规划展示:在地图上展示规划设计图