Zooming to an AutoCAD entity using JavaScript

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.
  • 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" "/wp-content/uploads/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.

29 responses to “Zooming to an AutoCAD entity using JavaScript”

  1. Kean you accidentally wrote c# code....
    kidding, its strikingly similar to C#, as if...on purpose?
    How did MS get away with making a language that seems to have copied Java?

  2. while here, it seems to me that Autodesk should use the java introduction to also re-embrace Autolisp.
    Most of the customization floating around is lisp, and its easy for a general cad manager to use for startup (acaddoc.lsp) and several other things, without climbing the .net mountain.
    I am thinking of VLIDE improvements, there are super basic mods needed that would not affect the actual syntax at all. Things like the ability to compile multiple projects batch style, and also not showing the console window every time debugging is stopped. It is a golden opportunity as you want people buying autocad, not acad lt, or bricscad. How much time was spent on this java addition? doubt it affects as many customers as lisp does.

  3. Java is different from JavaScript, but they and C# are all C-based (from a syntax perspective), so they'll inevitably look quite similar.

    Please do submit your requests for feature enhancements via the ADN team (or there's probably a discussion forum for that, too).

    We needed this layer (or something like it) to implement the Design Feed: I see it as a good thing that it was also made available externally.

    You'll see much more benefit when you're able to write an app that works across multiple platforms - desktop, web & mobile - which would have been very hard to do with LISP: each of these platforms has JavaScript built into it, as they all provide web access.

    Kean

  4. Is the JavaScript API available in AutoCAD for Mac?

  5. Good question. I don't believe so, but of course it's altogether feasible for it to be implemented, given the resources.

    When/whether it gets done is another question, of course.

    Kean

  6. Kean, is it possible to add a path to TRUSTEDDOMAINS (or TRUSTED PATHS) via code on C++ Object Arx? Or even, add it to any register entry on my plugin installer?

    Thank you

  7. Hi Kean,

    JavaScript programming on AutoCAD 2014 is very interesting. I already built a new technology preview called .NETScript that can drive AutoCAD (not only for 2014) locally and remotely. JavaScript uses .js files while .NETScript uses .ns files that can both load from the web and execute inside AutoCAD. The API will be different between them. Please check it out at http://www.netscriptcad.com

    Thank you.

  8. Lucas,

    You can use acedSetVar() from ObjectARX to do this, or you might write to the keys in "HKEY_CURRENT_USER\Software\Autodesk\AutoCAD\R19.1\ACAD-D001:409\Profiles\<<unnamed profile="">>\Variables", if you really needed to.

    For the domains, you might want to pick up the default value from here, to make sure you don't break anything by removing existing domains from the list: "HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD\R19.1\ACAD-D001\Variables\TRUSTEDDOMAINS".

    The best, of course, is to use Autoloader to avoid all of this.

    Kean

    1. Hi Kean.
      How to run JavaScript files offline in Autocad 2014?

      1. You can specify a "file://" URL to the .js file in the WEBLOAD command or the API used to load the file.

        Kean

        1. Thank you Kean.
          what use API for load file .js?
          Please Example.

          1. Take a look at Application.LoadJSScript() in .NET or acjsLoadJSScript() in ObjectARX.

            Kean

            1. Your answer is correct.
              But if I am connected to the Internet I read AutoCAD files.
              And if there is no internet connection, I have not read AutoCAD files.
              Why AutoCAD to read a file of these methods
              "file://"
              Application.LoadJSScript(System.uri)
              or install iis and
              http://localhost/filename.js
              Must be connected to the Internet.
              Otherwise, AutoCAD can not read the JavaScript file.

              1. It's probably because the files reference AutoCAD.js on the internet. You could copy that locally and refer to it from there, but that comes with the risk it'll be out of date.

                Kean

                1. Thank you Kean.

  9. Interesting, thank you.

    Kean

  10. Hi Kean,
    Downloading .js files is freaking-out my scanners. I'm probably not alone in this. I imagine there will be more samples, perhaps a different extension will solve this issue; either zipped, or append a .txt to the .js.

    Though I s'pose it's just as easy for us to do a SaveAs and add the extension .js.txt πŸ™‚

    I'll be interested in seeing where this addition leads.

    Regards
    Kerry

  11. Kean,
    I'm afraid you're loosing sight of the majority of customizers by downplaying the importance of the Lisp API.
    I'm sure if you go back and look at the developer surveys for the last few years you'll see what I mean.

  12. Hi Kerry,

    Exactly - and if you can't "save as", you should be able to take the code from the blog post and save it into a local file of your choosing. I could change the extension of the file on my blog, but that woould stop it from being loadable for those who don't have such files blocked.

    Agreed - will be interesting to see what comes of this.

    Cheers,

    Kean

  13. Kerry,

    I didn't mean to downplay the importance of LISP: I'm just saying we couldn't easily have used LISP to achieve what we want from this particular mechanism.

    Regards,

    Kean

  14. Kean,
    SaveAs will be fine thanks.
    Regards
    Stay well,

  15. Lucas G. Silva Avatar

    Thank you Kean.

    I guess the Autoloader is really the best option, as mentioned at this video from AutoDesk: goo.gl/QcIjU

    Use the acedSetVar() is also a interesting one, but it is an overload (for the programmers and for the plugin).

    Use the registry entry inside the installer is, in my option, the worst one, as it needs to be set for each profile.

    One more time, thank you!

  16. Kean
    Thank you for sharing so much useful codes.
    Inspired by your article about LeapJS and Paper.js, I am trying to use D3.js (d3js.org/) to solve points Delaunay problem recently.
    But I find that after I use this to obtain the object as you illustrated in this article.

    var entity = new Acad.DBEntity(z.objectId);
    // var ext = entity.getExtents();

    I find that except getExtents, I cant find entity's any other properties, just like the center of a circle. When I read a article of you, you say that "Given the fact the JavaScript API doesn't provide access to AutoCAD drawing objects – and there are currently no plans to provide this access"

    Is this means that I have to use getExtents to get a Point's position? or could you please recommend other ways? I really want to use web library to solve this problem, that is what Javascript API attract me.

    Thank you very much.

  17. You should be able to extend the "shaping layer" to get specific properties that you need. You'd have to implement an in-process (ObjectARX or .NET) component that is used in combination with your JS code.

    Kean

  18. Hi,Kean
    Thank you very much.
    I just learn from your another article (jig Circle) and learn this "shaping layer".
    Now I have solve this problem.
    Thank you again. Surely I hope that this could be included in the next version Javascript API.

  19. I can not find the function 'write', i'm using the autocad 2016。
    When I use β€˜write’ to print the message, error occurs : 'write' not defined!

    1. Yes, it turns out that disappeared somewhere along the way. I don't see an alternative, other than to send the information to a .NET module for display (or showing it directly in an HTML dialog).

      Kean

      1. Thank you, Kean!

Leave a Reply to Kerry Brown Cancel reply

Your email address will not be published. Required fields are marked *