As promised in yesterday’s post, here’s my first attempt at writing a simple JavaScript app for AutoCAD. This app is purely JavaScript – no HTML to be seen, anywhere – and implements a command inside AutoCAD that will zoom to the extents of an entity selected by the user.
Let’s start by looking at the source code, which has been posted here.
// Command to zoom to the extents of a selected entity
function zoomEntity() {
try {
// Set the options for our user prompt
var peo = new Acad.PromptEntityOptions();
peo.setMessageAndKeywords("\nSelect an entity", "");
peo.allowObjectOnLockedLayer = true;
// Ask the user to select an entity
Acad.Editor.getEntity(peo).then(onComplete, onError);
}
catch(e) {
write(e.message);
}
}
function onComplete(jsonPromptResult) {
try {
// Parse the JSON string containing the prompt result
var resultObj = JSON.parse(jsonPromptResult);
if (resultObj && resultObj.status == 5100) {
// If it was successful, get the selected entity...
var entity = new Acad.DBEntity(resultObj.objectId);
// ... and its extents
var ext = entity.getExtents();
// Zoom to the object's extents, choosing to animate the
// view transition (if possible to do so)
Acad.Editor.CurrentViewport.zoomExtents(
ext.minPoint3d, ext.maxPoint3d, true
);
}
}
catch(e) {
write(e.message);
}
}
function onError(jsonPromptResult) {
write("\nProblem encountered.");
}
// Add the command, we'll make it transparent
Acad.Editor.addCommand(
"ZOOM_CMDS",
"ZEN",
"ZEN",
Acad.CommandFlag.TRANSPARENT,
zoomEntity
);
write("\nRegistered ZEN command.\n");
A few things to note about this code:
- There are some things that are very familiar about it (e.g. the PromptEntityOptions class). Wherever possible we’ve tried to extend the “AutoCAD Object Model” you’ve become familiar with via .NET to the world of JavaScript.
- This should help reduce the cognitive dissonance when working with the new API.
- The selection method – getEntity() – returns a PromptEntityResult (again, familiar from the world of .NET), but in JavaScript this class implements the Promise pattern. Which means it implements the then() method to which you can pass callbacks that will get called depending on the results of the selection event.
- This approach of “continuation passing” is very common inside JavaScript and takes some getting used to. C# has the fantastic async/await capability that asks the compiler to care of the messiness that comes with asynchronous callbacks (they’re there, just not in your source code), but I don’t know of plans to add this to JavaScript. (It is coming to Python, though.)
- The onComplete() and onError() callbacks take a JSON string as an argument: we need to de-serialize this to get at the properties we’re looking for (in our case we care about status and objectId).
- The zoomExtents() method is pretty handy, and zooms to the specified extents rather than to those of the current drawing. It takes a flag that indicates whether you want AutoCAD to perform a smooth view transition, if it’s at all possible to do so. Pretty cool.
Regarding the development/deployment process…
It’s a bit tricky going back to JavaScript from the world of .NET, especially given how dependent we’ve (probably) all become on IntelliSense.
Now I expect there are text editors that provide syntax completion capabilities for arbitrary JavaScript libraries (you’ll find we have no reference in the code above to the Autodesk.AutoCAD.js file – this is assumed, which means any such editor would need to be configured to point to it), but the way I’ve enabled this within Visual Studio is to code within an HTML wrapper:
<html>
<head>
<script
type="text/javascript"
src="http://www.autocadws.com/jsapi/v1/Autodesk.AutoCAD.js">
</script>
<script type="text/javascript">
// You can code here...
</script>
</head>
<body/>
</html>
You can write your code in the area indicated above and receive at least some IntelliSense from Visual Studio, before copying and pasting to a separate .js file for deployment (assuming you have no HTML UI to deploy, of course).
You can then use the WEBLOAD command inside AutoCAD to load from the URL this code has been posted at (and you can do this now inside AutoCAD 2014 – you don’t need to post to your own URL, of course):
(command "_.WEBLOAD" "http://through-the-interface.typepad.com/files/ZoomEntity.js")
As mentioned in the last post, to avoid the security warning related to loading the code from this domain, you can add it to the TRUSTEDDOMAINS sysvar:
(setvar "TRUSTEDDOMAINS" (strcat (getvar "TRUSTEDDOMAINS") ";through-the-interface.typepad.com"))
When loaded, it’s then a simple matter of running the ZEN command and selecting an entity to which you’d like to zoom.
I did see a quirk related to this: the view modification operation did not get included in the undo stack. I’ll ask around to see whether that’s a deliberate choice, or not.
A bit of trickiness I came across when deploying to my blog (you can also WEBLOAD from a local folder, of course, which certainly makes sense while developing your code) is that the hosted browser (more on this in a future post where we’ll go under the cover on the implementation) seems to save a cache of the page for performance reasons. I so far haven’t been able to find a way to clear that cache, which means that I’ve resorted to posting different versions of the file under different names (which renders caching irrelevant and guarantees the latest code will be loaded at the expense of having lots of source files on the web to clean up, afterwards).
Right – I’m going to leave it there, for today. In the next post (which may well be tomorrow, as Friday is a holiday, here) we’ll take a look at a simple HTML5 UI – with some JavaScript included – which we’ll load into an AutoCAD palette.