Create Drawing Examples
Generate CAD Engineering Section Drawing from Frontend Data
Effect

What Features Does It Support?
- Supports creation of 27 CAD entity types, such as lines, text, hatches, etc.
- Supports modify, clone, and delete operations on entities in DWG drawings
- Supports creating CAD layers, linetypes, block definitions, and text styles
- Supports copying entities from external drawings into the current CAD drawing
- Supports creation and setting of block attribute text
- Created CAD geometry can be displayed directly in the frontend as GeoJSON, with selection and move support
- Created CAD geometry can be displayed in the frontend with click-to-show entity type and attributes
- Can export to DWG format
Implementation Principle

(1) Use templates for constant elements such as legends. Copy these entities directly when creating the drawing. For title blocks, insert from external drawings; fields that need to be edited (e.g. drafter, date) can be created as block attribute text and set during creation. The section drawing template above comes from these two template drawings.
Section drawing template: 
View section drawing template online
Title block template: (Unit and date are block attribute text; values can be set when inserting)

View title block template online
(2) Obtain the drawing data to create. The example uses simulated data.
(3) Create the relevant entities using the CAD entity creation methods provided by the VJMap https://vjmap.com/ SDK. Supported entity types include DbLine (line), DbCurve (curve), Db2dPolyline (2D polyline), Db3dPolyline (3D polyline), DbPolyline (polyline), BlockReference (block reference), DbArc (arc), DbCircle (circle), DbEllipse (ellipse), DbHatch (hatch), Text (single-line text), DbMText (multiline text), RasterImage (raster image), DbShape (shape), Spline (spline), Wipeout (wipeout), Dimension (dimension), Db2LineAngularDimension (angular dimension [two lines]), Db3PointAngularDimension (angular dimension [three points]), DbAlignedDimension (aligned dimension), DbArcDimension (arc dimension), DbDiametricDimension (diametric dimension), DbOrdinateDimension (ordinate dimension), DbRadialDimension (radial dimension), DbRadialDimensionLarge (radial dimension with leader), DbRotatedDimension (rotated dimension), AcDbAttributeDefinition (attribute definition), AcDbAttribute (block attribute), DbLayer (layer), DbTextStyle (text style), DbDimStyle (dimension style), DbLinetypeStyle (linetype style), DbBlock (block definition), DbDocument (database document).
Tips to reduce code:
- Tip 1: Copy entities from the template and modify their properties. This reduces parameters and code.
- Tip 2: For repeated objects, create blocks and define variable text as block attributes. Then create block references repeatedly and modify the attribute text.
(4) Build a JSON object from the created data and call the VJMap service to create the DWG drawing in the backend.
(5) Return the created DWG data to the frontend as GeoJSON or GIS tiles. For small drawings, GeoJSON works well. For large drawings, GeoJSON can be slow and affect rendering; use GIS raster or vector tiles instead.
Online Demo
https://vjmap.com/demo/#/demo/map/comprehensive/03datatodwgmap
Auto-Generate from Template Data
Auto-generate and export DWG from a CAD template using data
CAD template: View CAD template online

// --Auto-generate from template data--Auto-generate and export DWG from a CAD template using data
// Template map ID and version
let templateId = "sys_drawtemplate";
let templateSecVersion = "v1";
let svc = new vjmap.Service(env.serviceUrl, env.accessToken);
// Note: objectids below can be obtained by:
// Opening the template in VJMap Cloud Platform in Memory mode, clicking the entity, and reading the object value in the attributes panel
// Or opening the template in Geometry Rendering mode, clicking the entity, and reading the object value in the attributes panel. For block entities (objectid with multiple _), use the string before the first _
let symbols = {
"symbol1": "8F9",// symbol1 objectid
"symbol2": "92A" ,// symbol2 objectid
}
let lineObjectId = "905"; // line objectid
let arrowObjectId = "909"; // arrow objectid
let textObjectId = "8FA"; // text objectid
// Mock data
const mockData = (num) => {
num = num || 5;
let lines = []
for(let i = 0; i < num; i++) {
let items = {
points: [],
textColor: vjmap.randomColor(),
lineColor: vjmap.randomColor(),
arrowColor: vjmap.randomColor()
}
for(let k = 0; k < 3; k++) {
items.points.push({
symbol: (k % 2 == 0) ? "symbol1" : "symbol2", // Mock: even points use symbol1, odd use symbol2
text: "CY" + vjmap.randInt(0, 1000), // Random text value
position: [vjmap.randInt(-50, 50), vjmap.randInt(-50, 50)],
symbolColor: vjmap.randomColor()
})
}
lines.push(items);
}
return lines
}
// Create drawing
const createDoc = async (Data) => {
// Get drawing data
let drawData = Data;
let doc = new vjmap.DbDocument();
// Data source
doc.from = `${templateId}/${templateSecVersion}`;
// Clear all data from source (this template does not need clearing, used as-is)
doc.isClearFromDb = true;
let entitys = [];
// All lines
for(let ln = 0; ln < drawData.length; ln++) {
let lineItem = drawData[ln];
let textColor = lineItem.textColor; // Text color
let lineColor = lineItem.lineColor; // Line color
let arrowColor = lineItem.arrowColor; // Arrow color
// All points on the line
for(let pt = 0; pt < lineItem.points.length; pt++) {
let point = lineItem.points[pt];
entitys.push(new vjmap.DbBlockReference({
cloneObjectId: symbols[point.symbol],
position: point.position,
color: vjmap.htmlColorToEntColor(point.symbolColor)
}))
entitys.push(new vjmap.DbText({
cloneObjectId: textObjectId,
position: [point.position[0], point.position[1]-0.5],
horizontalMode: vjmap.DbTextHorzMode.kTextCenter, // kTextCenter
verticalMode: vjmap.DbTextVertMode.kTextTop, // kTextVertMid,
color: vjmap.htmlColorToEntColor(textColor)
}))
if (pt != 0) {
// Create line between two points
let startPt = lineItem.points[pt - 1].position;
let endPt = lineItem.points[pt].position;
entitys.push(new vjmap.Db2dPolyline({
cloneObjectId: lineObjectId,
points: [startPt, endPt],
color: vjmap.htmlColorToEntColor(lineColor)
}))
// Create arrow at midpoint
let midPt = [(startPt[0] + endPt[0]) / 2.0, (startPt[1] + endPt[1]) / 2.0];
entitys.push(new vjmap.DbBlockReference({
cloneObjectId: arrowObjectId,
position: midPt,
// Rotation
matrix: [
{
op: "rotate", // Rotate
angle: vjmap.geoPoint(startPt).angleTo(vjmap.geoPoint(endPt)), // Radians
origin: midPt // Rotation center
}
],
color: vjmap.htmlColorToEntColor(arrowColor)
}))
let arrowTextPoint = [midPt[0], midPt[1] + 1];
let arrowTextAngle = vjmap.geoPoint(startPt).angleTo(vjmap.geoPoint(endPt));
if (arrowTextAngle > Math.PI / 2 && arrowTextAngle < Math.PI * 3 / 2 ) {
// Keep text upright
arrowTextAngle += Math.PI
}
// Text above arrow
entitys.push(new vjmap.DbText({
cloneObjectId: textObjectId,
position: arrowTextPoint,
horizontalMode: vjmap.DbTextHorzMode.kTextCenter, // kTextCenter
verticalMode: vjmap.DbTextVertMode.kTextVertMid, // kTextVertMid,
color: vjmap.htmlColorToEntColor(arrowColor),
// Rotation
matrix: [
{
op: "rotate", // Rotate
angle: arrowTextAngle, // Radians
origin: arrowTextPoint // Rotation center
}
],
}))
}
}
}
doc.entitys = entitys;
return doc;
}
// Set an initial bounds for the map (exact values do not matter). Final DWG export will compute real bounds from entity coordinates.
let mapBounds = '[-10000,-10000,10000,10000]'
let mapExtent = vjmap.GeoBounds.fromString(mapBounds);
mapExtent = mapExtent.square(); // Convert to square
svc.setCurrentMapParam({
darkMode: true, // Set dark mode since no map opened yet
bounds: mapExtent.toString()
})
// Create coordinate system
let prj = new vjmap.GeoProjection(mapExtent);
// Create map object
let map = new vjmap.Map({
container: 'map', // container ID
style: {
version: svc.styleVersion(),
glyphs: svc.glyphsUrl(),
sources: {},
layers: []
},// Vector tile style
center: [0,0], // Center
zoom: 2,
renderWorldCopies: false
});
// Attach service and projection to map
map.attach(svc, prj);
// Fit map to bounds
map.fitMapBounds();
await map.onLoad();
// Create geometry data
const createGeomData = async (map, doc) => {
let svc = map.getService();
let res = await svc.cmdCreateEntitiesGeomData({
filedoc: JSON.stringify(doc)
});
if (res.error) {
message.error(res.error);
return {
type: "FeatureCollection",
features: []
};
}
if (res.metadata && res.metadata.mapBounds) {
// If metadata contains map bounds, update map extent
map.updateMapExtent(res.metadata.mapBounds);
}
const features = [];
if (res && res.result && res.result.length > 0) {
for (let ent of res.result) {
if (ent.geom && ent.geom.geometries) {
let clr = map.entColorToHtmlColor(ent.color); // Entity color to HTML color
let featureAttr = {};
// Distinguish line and polygon colors for composite entities
if (ent.isPolygon) {
featureAttr.color = clr; // Fill color, polygons only
featureAttr.noneOutline = true; // No polygon outline, polygons only
} else {
featureAttr.color = clr; // Color
featureAttr.line_width = ent.lineWidth; // Line width
}
for(let g = 0; g < ent.geom.geometries.length; g++) {
if (ent.geom.geometries[g].type == "Point") {
// Convert to line with same start and end
ent.geom.geometries[g].type = "LineString";
ent.geom.geometries[g].coordinates = [
ent.geom.geometries[g].coordinates, // Start
ent.geom.geometries[g].coordinates // End
]
}
}
let ft = {
id: vjmap.RandomID(10),
type: "Feature",
properties: {
objectid: ent.objectid,
opacity: ent.alpha / 255,
...featureAttr,
}
}
if (ent.geom.geometries.length == 1) {
features.push({
...ft,
geometry: ent.geom.geometries[0],
});
} else {
features.push({
...ft,
geometry: {
geometries: ent.geom.geometries,
type: "GeometryCollection"
},
});
}
}
}
}
return {
type: "FeatureCollection",
features: features,
};
};
// Clear previous map data
const clearMapData = () => {
svc.setCurrentMapParam({
darkMode: true, // Set dark mode since no map opened yet
bounds: mapExtent.toString()
})
map.disableLayerClickHighlight();
map.removeDrawLayer();
let sources = map.getStyle().sources;
for(let source in sources) {
map.removeSourceEx(source);
}
}
// Create map with data
const createDataMap = async (doc) => {
clearMapData();
let geojson = await createGeomData(map, doc);
map.getDrawLayer().set(geojson);
}
// Create DWG map
const createDwgMap = async (doc) => {
// Clear previous drawing first
clearMapData();
// js code
let res = await svc.updateMap({
// Get temporary map id (temporary maps auto-delete when expired)
mapid: vjmap.getTempMapId(1), // Temp map auto-delete time in minutes when not viewed. Default 30
filedoc: JSON.stringify(doc),
mapopenway: vjmap.MapOpenWay.Memory,
style: {
backcolor: 0 // Set to 0xFFFFFF if div background is light
}
})
if (res.error) {
message.error(res.error)
}
await map.switchMap(res);
}
let curDoc;
const exportDwgOpen = async () => {
if (!curDoc) return;
const mapid = 'exportdwgmap';
let res = await svc.updateMap({
mapid: mapid,
filedoc: JSON.stringify(curDoc),
mapopenway: vjmap.MapOpenWay.Memory,
style: {
backcolor: 0 // Set to 0xFFFFFF if div background is light
}
})
if (res.error) {
message.error(res.error)
} else{
window.open(`https://vjmap.com/app/cloud/#/map/${res.mapid}?version=${res.version}&mapopenway=Memory&vector=false`)
}
}
const creatDataMap = async () => {
let Data = mockData(5);
const doc = await createDoc(Data);
await createDataMap(doc);
map.fitMapBounds();
curDoc = doc;
}
const creatDwgMap = async () => {
let Data = mockData(15);
const doc = await createDoc(Data);
await createDwgMap(doc);
map.fitMapBounds();
// Highlight on click (elements highlight when clicked)
map.enableLayerClickHighlight(svc, e => {
if (!e) return;
let msg = {
content: `type: ${e.name}, id: ${e.objectid}, layer: ${e.layerindex}`,
key: "layerclick",
duration: 5
}
e && message.info(msg);
})
curDoc = doc;
}
// Generate random drawing
creatDataMap();
const mousePositionControl = new vjmap.MousePositionControl();
map.addControl(mousePositionControl, "bottom-left");