Liav Koren // artisanal electrons // handcrafted pixels.

Previewing 3D files locally.

23 Oct 2013

I've been working a STL quotation service for Andre Tiemann, of Draftprint3D. The Draftprint site already used JSC3D, a canvas-based Javascript 3d library that I wasn't familiar with. JSC3D is definately an interesting looking project, but it's still fairly young, and not as well documented as it could be.

One feature I really wanted to be able to implement for Andre was local previewing of 3d CAD files. It would have been fairly straight-forward to shoot the files up to the server and then transfer them back to the preview page -- this in fact does happen eventually in order to process the file for quoting, however it seemed insane to have to hit to server in order for the user to just get a preview of the file.

Using the File API, it was relatively easy to get local preview working, however there were one or two non-obvious things -- I had to spend a while poking through JSC3D source in order to figure it out, and I needed a pointer from Humu, JSC's maintainer, to fix one bug in the code.

You can drag and drop an 3D STL file into this rendering canvas. JSC3D also allows models to be rotated and zoomed in/out: drag with your left mouse button in the canvas for rotation, mouse-wheel to zoom. Occasionally the drag/drop event doesn't fire correctly when a dropping a file into the canvas -- just hit reload if you have any hiccups.

Here's how to get JSC3D to load a local file using the File API:

//initalize the JSC3D viewer. This is a singleton -- only one per canvas:
var viewer = new JSC3D.Viewer(mycanvas)
  //this is a handler for a input[file] object.
  //You can also use a drag/drop handler.
  var handle_file_select = function(e) {
    e.stopPropagation()
    e.preventDefault()
    var file = e.target.files[0]
    preview_stl(file)
  }

  function preview_stl(file) {
    var theScene
    var stl_loader
    var reader = new FileReader()
    function setup_viewer() {
      viewer.setParameter('InitRotationX', 20);
      viewer.setParameter('InitRotationY', 20);
      viewer.setParameter('InitRotationZ', 0);
      viewer.setParameter('ModelColor', '#CAA618');
      viewer.setParameter('BackgroundColor1', '#FFFFFF');
      viewer.setParameter('BackgroundColor2', '#383840');
      viewer.setParameter('RenderMode', "flat");
    }
    setup_viewer()

    //This closure pattern was inspired by HTML5Rocks' article on the File
    //API. Inside it we put the JSC3D payload which initializes the scene when
    //we pass a new STL file. I haven't seen this usage of parseStl() method
    //documented elsewhere.
    reader.onload = (function(file) {
      return function(e) {
        theScene = new JSC3D.Scene
        stl_loader = new JSC3D.StlLoader()
        stl_loader.parseStl(theScene, e.target.result)
        viewer.init()
        viewer.replaceScene(theScene)
        viewer.update()
      }
    })(f)
  }