Just to complement yesterday’s post showing how to define a simple jig using JavaScript, here’s the same code from a separate .js file:
var doc = Acad.Application.activedocument;
var center = new Acad.Point3d(0, 0, 0);
var radius = 0;
var trId;
function pointToString(pt) {
var ret =
pt.x.toString() + "," +
pt.y.toString() + "," +
pt.z.toString();
return ret;
}
function createCircle(cen, rad, first) {
// Build an XML string containing data to create
// an AcGiTransient that represents the circle
var cursor = '';
var drawable =
'<?xml version="1.0" encoding="utf-8"?>' +
'<drawable ' +
'xmlns="http://www.autodesk.com/AutoCAD/drawstream.xsd" ' +
'xmlns:t="http://www.autodesk.com/AutoCAD/transient.xsd" '+
't:onmouseover="onmouseover"' + cursor + '>' +
'<graphics id="id1"><circle center ="' + pointToString(cen) +
'" radius ="' + rad.toString() + '"/>' +
'</graphics></drawable>';
return drawable;
}
function circleJig() {
function onJigUpdate(args) {
var res = JSON.parse(args);
if (res) {
// The value being updated is the distance
radius = res.distance;
// Use it to create the XML for a transient
// circle and ask for it to be displayed
var x = createCircle(center, radius);
doc.transientManager.updateTransient(trId, x);
}
return true;
}
function onJigComplete(args) {
// When the jig is over, remove the transient
doc.transientManager.eraseTransient(trId);
var res = JSON.parse(args);
if (res && res.dragStatus == Acad.DragStatus.kNormal) {
Acad.Editor.executeCommandAsync(
'_.CIRCLE ' + pointToString(center) + ' ' + radius
);
}
}
function onJigError(args) {
write('\nUnable to create circle: ' + args);
}
function onPointSelected(args) {
var res = JSON.parse(args);
if (res) {
center =
new Acad.Point3d(
res.value.x,
res.value.y,
res.value.z
);
// Now we can create our transient
var tran = new Acad.Transient();
trId = tran.getId();
// And ask for it to be drawn
var x = createCircle(center, 0, true);
doc.transientManager.addTransient(tran, x);
// Set up our jig options
var opts =
new Acad.JigPromptDistanceOptions('Point on radius');
opts.basePoint = center;
opts.useBasePoint = true;
// Run the jig to select the distance
var jig = new Acad.DrawJig(onJigUpdate, opts);
Acad.Editor.drag(jig).then(onJigComplete, onJigError);
}
}
function onPointError(args) {
write('\nUnable to select point: ' + args);
}
// Ask the user to select the center point before we
// start the jig
var opts = new Acad.PromptPointOptions('Select center');
Acad.Editor.getPoint(opts).then(
onPointSelected, onPointError
);
}
Acad.Editor.addCommand(
"JIG_CMDS",
"CJ",
"CJ",
Acad.CommandFlag.MODAL,
circleJig
);
You can test this without the need for a separate .NET loader by just copying this into the command-line in AutoCAD 2014:
(command "_.WEBLOAD" "http://through-the-interface.typepad.com/files/CircleJig.js")
Then you should be able to run the CJ command to jig a circle from JavaScript.
Again, you’ll see the issue related to clicking the point on the radius (unless it’s system-specific, which would surprise me a great deal), but it’ll give you a sense of the kind of responsiveness to expect from a JavaScript-implemented jig.
On a general note, I’ve been finding that it’s simplest to code within a full HTML page – as the reference to the AutoCAD Shaping Layer JavaScript file gives more useful IntelliSense. It does mean you need a .NET loader module to test, but once you have it set up, it’s there. What’s also very handy about this approach is that each time the loader command (in my case it’s called JSP) is run, it reloads the palette from wherever it’s located. So you can change the code and re-run the loader command without restarting AutoCAD (something that’s really entered into muscle memory after all these years of developing with .NET and not having Edit & Continue). One caveat to this is if your code causes the AcWebBrowser to crash: if that’s the case (and it’s pretty common, at least with my code ;-) then you’ll need to restart AutoCAD.
I also tend to load the HTML page from the local file system (using a URL such as “file://C:\Path\To\MyPalette.html” in the loader module), as this avoids the pain of having to push it to a web-server and deal with the caching issues when loading. It may not have been obvious from prior posts that you can load from a local file system, so I should confirm that it’s possible and furthermore works very well.
In terms of debugging, I’ve been using the technique shown in Fenton’s very handy blog post to enable some level of debugging of HTML-defined palettes (another advantage over a separate .js loaded via WEBLOAD). The server that hosts the HTML inspector tool has changed, however – the URL needs to be changed to “http://drawingfeed.visualtao.net/DevTools/inspector/devtools.html” – but I’m sure the DevBlog post will be updated soon (and may well have been by the time many of you end up reading this).
That said, I still find I’m inserting lots of write() statements into my code (which causes messages to be written to the AutoCAD command-line, the equivalent of acutPrintf() or Editor.WriteMessage()). Maybe that’s another bit of (this time web-development focused) muscle memory that I’ve retained in spite of the world having moved on, but I find it’s a quick enough way of working out what’s going on in the code. Once I get around to using more capabilities provided by the JavaScript debugger, I’ll hopefully find I can afford to unlearn this particular behaviour, but then the fact the debugger also gets blown away when AcWebBrowser crashes means there are a lot of scenarios that write() is still better suited to report on.