Sunday, April 14, 2013

Code and Visualization Side-By-Side

‹prev | My Chain | next›

JavaScript scope issues aside, it was surprisingly easy to get multiple instances of the ICE Code Editor embedded on the same web page. There are still a few features that I would like to add to the embedded version of ICE (ability to hide the code layer, disable the visualization when not in the viewport, scroll the code to a line number, open in full editor), but first I want to add the option to separate the visualization and code editing layers on web pages.

I really like the code-on-top-of-the-visualization approach first started by Mr.doob in his code editor (from which ICE is forked). It works really well for readers of 3D Game Programming for Kids and in various hackathons that we run with school groups:

But there are times when writing about code in blog posts that it might help to have the code and visualization layers side-by-side instead of on top of each other:

I start by converting my embedded sample page to a side-by-side version. In this page, I use a table:
<table width="100%">
<script type="text/ice-code" id="code-001">
  // Code goes here...
<div id="preview-001"/>
I will want to supply the code-001 and preview-001 elements to the embedded version of the code instead of the single, combined element that is currently used.

The first pass that I take for the API is to optionally pass the preview element to the constructor:
    new ICE.Embedded(
      {preview_el: document.getElementById('code-001')}
Mostly, this seems the least invasive first pass, but it might be a reasonable approach. If the optional preview_el is not supplied, then create one behind the code editor.

To make this happen, I need to propagate that optional element from the ICE.Embedded class:
function Embedded(script, options) {
  this.script = script;
  if (!options) options = {};
  // ...
  this.editor = new ICE.Editor(this.el, {
    preview_el: options.preview_el,
    // ...
  // ...
And honor the preview element in the ICE.Editor constructor:
function Editor(el, options) {
  this.el = el;

  if (typeof(options) != "object") options = {};
  // ...
  this.preview_el = options.preview_el || this.createPreviewElement();
  // ...
Surprisingly, that is all that is needed to get the preview layer on the side:

The positioning of that certainly leaves something to be desired, but as a proof of concept, I will take this as a win. I am more than a little surprised that it was that easy. This may validate the refactoring approach that I have taken over the last few days. Then again, the devil may be in the details of the positioning of that preview layer. Both the regular embedded and full-screen versions of ICE still work. But will they if I get the positioning right on the side-by-side view?

I will find out tomorrow.

Day #722

No comments:

Post a Comment