CAD Viewer Showcase Demo Sample Code

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, DXF.
  • View and edit the files as PDF documents
  • Save as PDF or PNG.

Implementation steps
To add CAD Viewer capability with WebViewer:

Step 1: Choose your preferred web stack
Step 2: Download required modules listed in the Demo Dependencies section below
Step 3: Add the ES6 JavaScript sample code provided in this guide

Demo Dependencies
This sample uses the following:

Want to see a live version of this demo?

Try the CAD Viewer demo

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

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales