CAD Viewer Showcase Demo Code Sample

Requirements
View Demo

Easily create a visualization tool for AutoCAD's DWG and DXF files. View, edit, and annotate those files as PDF files from the browser.

This demo allows you to:

  • Load AutoCAD Files: DWG, DWF, DXF, DGN, and RVT.
  • View and edit the files as PDF documents
  • Save as PDF or PNG.

Don't need the WebViewer UI component or need a different server language? Check out the Server SDK CAD Conversion sample code.

Implementation steps

To add CAD Viewer capability in Node.js with Server and WebViewer:
Step 1: Get started with Server SDK in Node.js
Step 2: Download the CAD Module
Step 3: Get started in your preferred web stack for WebViewer
Step 4: Add the ES6 JavaScript sample code provided in this guide

Once you generate your license key, it will automatically be included in your sample code below.

License Key

1// ES6 Compliant Syntax
2// GitHub Copilot v1.0, GPT-4.1, September 29, 2025
3// File: index.js
4
5import WebViewer from '@pdftron/webviewer';
6
7const licenseKey = 'YOUR_WEBVIEWER_LICENSE_KEY';
8
9// CAD Viewer Demo
10//
11// This code demonstrates how to view CAD files directly in the browser with the Apryse JavaScript document SDK.
12// It shows how to create a display and visualization tool for AutoCAD floor plans and drawings.
13// Allowing users to view, edit, and annotate AutoCAD DWG CAD files from the browser using the WebViewer Server.
14//
15// **Important**
16// 1. You must get a license key from Apryse for the server to run.
17// A trial key can be obtained from:
18// https://docs.apryse.com/core/guides/get-started/trial-key
19//
20// 2. You need to also run the `npm install` command at /cad-viewer/server/ location to install the `@pdftron/pdfnet-node` and `@pdftron/cad` packages.
21
22// Initialize WebViewer with the specified settings
23function initializeWebViewer() {
24
25 // This code initializes the WebViewer with the basic settings
26 WebViewer({
27 path: '/lib',
28 licenseKey: licenseKey,
29 enableFilePicker: false,
30 }, element).then((instance) => {
31 // Enable the measurement toolbar so it appears with all the other tools, and disable Cloudy rectangular tool
32 const cloudyTools = [
33 instance.Core.Tools.ToolNames.CLOUDY_RECTANGULAR_AREA_MEASUREMENT,
34 instance.Core.Tools.ToolNames.CLOUDY_RECTANGULAR_AREA_MEASUREMENT2,
35 instance.Core.Tools.ToolNames.CLOUDY_RECTANGULAR_AREA_MEASUREMENT3,
36 instance.Core.Tools.ToolNames.CLOUDY_RECTANGULAR_AREA_MEASUREMENT4,
37 ];
38 instance.UI.enableFeatures([instance.UI.Feature.Measurement, instance.UI.Feature.Initials]);
39 instance.UI.disableTools(cloudyTools);
40
41 // Set default toolbar group to Annotate
42 instance.UI.setToolbarGroup('toolbarGroup-Annotate');
43
44 // Set default tool on mobile devices to Pan.
45 if (UIElements.isMobileDevice()) {
46 instance.UI.setToolMode(instance.Core.Tools.ToolNames.PAN);
47 }
48
49 instance.Core.documentViewer.addEventListener('documentUnloaded', () => {
50 if (searchParams.has('file')) {
51 searchParams.delete('file');
52 history.replaceState(null, '', '?' + searchParams.toString());
53 }
54 });
55
56 instance.Core.annotationManager.enableAnnotationNumbering();
57 instance.UI.NotesPanel.enableAttachmentPreview();
58
59 // Add the demo-specific functionality
60 customizeUI(instance).then(() => {
61 // Create UI controls after demo is initialized
62 UIElements.createUIControls(instance);
63 });
64 });
65}
66
67// CAD files, Key is the file name, value is the URL
68const CAD_FILES = {
69 'DWG': 'https://apryse.s3.us-west-1.amazonaws.com/public/files/samples/construction%20drawings%20color.dwg',
70 'DXF': 'PROVIDE_URL_HERE/*.dxf',
71};
72
73const defaultDoc = CAD_FILES['DWG']; // Default CAD file to load
74
75// Default styles for measurement tools
76const DEFAULT_FONT_SIZE = 16;
77window.DEFAULT_FONT_SIZE = DEFAULT_FONT_SIZE;
78const DEFAULT_STROKE_THICKNESS = 2;
79window.DEFAULT_STROKE_THICKNESS = DEFAULT_STROKE_THICKNESS;
80const MEASUREMENT_TOOLS = [
81 'AnnotationCreateDistanceMeasurement',
82 'AnnotationCreatePerimeterMeasurement',
83 'AnnotationCreateAreaMeasurement',
84];
85
86window.MEASUREMENT_TOOLS = MEASUREMENT_TOOLS;
87
88const customizeUI = async (instance) => {
89 const { Feature } = instance.UI;
90 const { Annotations, documentViewer } = instance.Core;
91
92 instance.UI.enableFeatures([Feature.Measurement]);
93 instance.UI.enableTools(MEASUREMENT_TOOLS);
94 instance.UI.openElements(['tabPanel']);
95 instance.UI.setActiveLeftPanel('layersPanel');
96
97 // Update default tool styles
98 MEASUREMENT_TOOLS.forEach((tool, index) => {
99 documentViewer.getTool(tool).setStyles({
100 StrokeThickness: DEFAULT_STROKE_THICKNESS / documentViewer.getZoomLevel(),
101 StrokeColor: new Annotations.Color(
102 255 * Number(index === 0),
103 255 * Number(index === 1),
104 255 * Number(index === 2),
105 ),
106 });
107 });
108
109 // Update font size to be larger
110 Annotations.LineAnnotation.prototype['constant']['FONT_SIZE'] = DEFAULT_FONT_SIZE / documentViewer.getZoomLevel() + 'px';
111 Annotations.LineAnnotation.prototype['constant']['TEXT_COLOR'] = '#FF0000';
112 documentViewer.addEventListener('zoomUpdated', (zoom) => UIElements.zoomUpdated(instance, zoom));
113
114 // Using the Apryse CAD Module, Convert and Load default document
115 const cadUrl = defaultDoc;
116 const cadFilename = cadUrl.split('/').pop();
117 const response = await fetch(defaultDoc);
118 if (!response.ok) {
119 throw new Error(`Failed to fetch CAD: ${response.status}`);
120 }
121 const cadBuffer = await response.arrayBuffer();
122 const pdfBuffer = await convertCadtoPdf(cadBuffer, cadFilename);
123 instance.UI.loadDocument(pdfBuffer, {
124 extension: 'pdf',
125 });
126};
127
128const convertCadtoPdf = async (cadBuffer, cadFilename) => {
129 // Send the CAD to the server to be converted to PDF
130 console.log('Sending CAD to server for conversion...');
131 const cadBlob = new Blob([cadBuffer]);
132 const formData = new FormData();
133 formData.append('cadfile', cadBlob, cadFilename);
134
135 const postResponse = await fetch('http://localhost:5050/server/handler.js', {
136 method: 'POST',
137 body: formData,
138 });
139
140 if (postResponse.status !== 200) {
141 throw new Error(`Server error during CAD upload: ${postResponse.status}`);
142 }
143 const buffer = await postResponse.arrayBuffer();
144 return buffer;
145};
146
147// Make convertCadtoPdf globally available
148window.convertCadtoPdf = convertCadtoPdf;
149const searchParams = new URLSearchParams(window.location.search);
150const history = window.history || window.parent.history || window.top.history;
151const element = document.getElementById('viewer');
152
153// Cleanup function for when the demo is closed or page is unloaded
154const cleanup = (instance) => {
155 const { Feature } = instance.UI;
156
157 if (typeof instance !== 'undefined' && instance.UI) {
158 instance.UI.disableTools(MEASUREMENT_TOOLS);
159 instance.UI.disableFeatures([Feature.Measurement]);
160 instance.UI.closeElements(['leftPanel']);
161 console.log('Cleaning up cad-viewer demo');
162 }
163};
164
165// Register cleanup for page unload
166window.addEventListener('beforeunload', () => cleanup(instance));
167window.addEventListener('unload', () => cleanup(instance));
168
169//helper function to load the ui-elements.js script
170function loadUIElementsScript() {
171 return new Promise((resolve, reject) => {
172 if (window.UIElements) {
173 console.log('UIElements already loaded');
174 resolve();
175 return;
176 }
177
178 const script = document.createElement('script');
179 script.src = '/showcase-demos/cad-viewer/client/ui-elements.js';
180 script.onload = function () {
181 console.log('✅ UIElements script loaded successfully');
182 resolve();
183 };
184 script.onerror = function () {
185 console.error('Failed to load UIElements script');
186 reject(new Error('Failed to load ui-elements.js'));
187 };
188 document.head.appendChild(script);
189 });
190}
191
192// Load UIElements script first, then initialize WebViewer
193loadUIElementsScript().then(() => {
194 initializeWebViewer();
195}).catch((error) => {
196 console.error('Failed to load UIElements:', error);
197});
198

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales