Overlay WebCAD on top of a vjmap map to achieve integrated CAD + GIS display.
CadMapOverlay is a lightweight CAD overlay layer that can be added to a vjmap map. It supports:
- Displaying CAD entities on the map
- Entity selection and interaction
- View synchronization (pan / zoom / rotate)
- Independent coordinate system management
// Dynamically load vjmap (if not already loaded)
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('Failed to load vjmap'));
document.head.appendChild(script);
});
};
const vjmap = await loadVjmap();
// Create vjmap service
const svc = new vjmap.Service(env.serviceUrl, env.accessToken);
// Open map
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);
// Create map instance
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();
const { CadMapOverlay, LineEnt, CircleEnt, TextEnt } = vjcad;
// Create CAD overlay
const cadOverlay = new CadMapOverlay({
bounds: mapExtent, // Map bounds
serviceUrl: env.serviceUrl, // Service URL
accessToken: env.accessToken, // Access token
themeMode: 0, // Theme: 0 = dark, 1 = light
enableSelection: true, // Enable selection
smoothAnimation: true, // Smooth animation
onSelectionChanged: (selection) => {
if (selection.length === 0) {
console.log("Selection cleared");
} else {
console.log(`Selected ${selection.length} entities`);
selection.forEach((ent, i) => {
console.log(` [${i + 1}] ${ent.type}`);
});
}
}
});
// Add to map
await cadOverlay.addTo(map);
const { LineEnt, CircleEnt, TextEnt } = vjcad;
// Get CAD coordinate bounds
const bounds = cadOverlay.getCadBounds();
const [minX, minY, maxX, maxY] = bounds;
// Create entities
const entities = [];
// Line
const line = new LineEnt([minX + 100, minY + 100], [maxX - 100, maxY - 100]);
line.setDefaults();
line.color = 1;
entities.push(line);
// Circle
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);
// Text
const text = new TextEnt();
text.insertionPoint = [centerX, centerY + 100];
text.text = "WebCAD";
text.height = 20;
text.setDefaults();
text.color = 5;
entities.push(text);
// Add entities in batch
cadOverlay.addEntities(entities);
// Zoom to extents
cadOverlay.zoomToExtents();
// Show/hide overlay
cadOverlay.setVisible(true); // Show
cadOverlay.setVisible(false); // Hide
// Get CAD coordinate bounds
const bounds = cadOverlay.getCadBounds();
// Returns: [minX, minY, maxX, maxY]
// Enable/disable selection
cadOverlay.enableSelection = true;
cadOverlay.enableSelection = false;
// Clear selection
cadOverlay.clearSelection();
// Listen for selection changes (configured in constructor)
const cadOverlay = new CadMapOverlay({
// ...
onSelectionChanged: (selection) => {
console.log(`Selected ${selection.length} entities`);
}
});
// Get the internal MainView instance
const cadView = cadOverlay.getCadView();
// Use the full WebCAD API
const Engine = cadView.Engine;
Engine.zoomExtents();
| Option | Type | Description |
|---|
bounds | GeoBounds | Map bounds (required) |
serviceUrl | string | Backend service URL |
accessToken | string | Access token |
themeMode | number | Theme: 0 = dark, 1 = light |
enableSelection | boolean | Whether to enable selection (default true) |
smoothAnimation | boolean | Whether to enable smooth animation (default true) |
onSelectionChanged | function | Selection-change callback |
| Value | Behavior |
|---|
true | Use CSS transform for smooth transitions and redraw after animation ends |
false | Real-time redraw mode, more responsive but may jitter |
| Method | Description |
|---|
addTo(map) | Add to a vjmap map |
getCadView() | Get internal MainView instance |
addEntities(entities) | Add entity array |
getCadBounds() | Get CAD coordinate bounds |
zoomToExtents() | Zoom to extents |
setVisible(visible) | Set visibility |
clearSelection() | Clear selection |
| Property | Type | Description |
|---|
enableSelection | boolean | Whether selection is enabled |
const {
CadMapOverlay,
LineEnt, CircleEnt, TextEnt,
CadEventManager, CadEvents,
message
} = vjcad;
// === 1. Initialize 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. Create CAD overlay ===
const cadOverlay = new CadMapOverlay({
bounds: mapExtent,
serviceUrl: env.serviceUrl,
accessToken: env.accessToken,
themeMode: 0,
enableSelection: true,
onSelectionChanged: (selection) => {
message.info(`Selected ${selection.length} entities`);
}
});
await cadOverlay.addTo(map);
// === 3. Add entities ===
const bounds = cadOverlay.getCadBounds();
const [minX, minY, maxX, maxY] = bounds;
const avgSize = Math.min(maxX - minX, maxY - minY) / 20;
const entities = [];
// Create 10 random entities
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. Interaction ===
// Click entities to select them
// Press ESC to clear selection
// Pan / zoom / rotate the map and the CAD view stays synchronized
- GIS + CAD integration: overlay CAD graphics on a map
- Equipment annotation: annotate equipment information at geographic locations
- Pipeline overlay: overlay CAD pipeline drawings on maps
- Planning display: show planning and design drawings on a map