Bounding box drag-select for tables; Javascript, Prototype

December 7th, 2007 posted by codders

*sigh*. I had a table, a lovely table. I wanted to be able to drag a bounding box around rows in the table. Looking around, there didn’t seem to be much by way of existing support, so I wrote this fine bounding box library. Well, it’s not actually that fine, but it does at least work in a cross-browser way. (Tested in FF/Linux, IE6/Linux, Opera/Linux, IE7/Win – IE7 has some minor alignment issues). I’m using it on tables here, but it’ll work (as far as I know) for any element.

A 1 B 1 C 1 D 1
A 2 B 2 C 2 D 2
A 3 B 3 C 3 D 3

The magic code to do what you see there is (with apologies for the fromCharCode: Javascript + WordPress = Death):

<script type="text/javascript" src="/script/prototype.js"></script>
<script type="text/javascript" src="/script/boundingbox.js"></script>
<script>
  // Button actions
  function doStuff()
  {
    var b = new BoundingBox();
    clearCells();
    updateLabel("Click and drag to select items");
    b.startSelection(releaseCallback);
  }

  function doStuff2()
  {
    var b = new BoundingBox();
    clearCells();
    updateLabel("Click mouse on canvas to start selection");
    b.startTwoClickSelection(firstClickCallback, releaseCallback);
  };

  // Callbacks
  function firstClickCallback()
  {
    updateLabel("Click mouse on canvas again to stop selection");
  };

  function releaseCallback(selected)
  {
    for (var i=0; i<selected.length; i++)
    {
      $(selected[i]).setStyle({
         background: "#FF9999"
       });
    }
    updateLabel("Click a button to begin selection");
  };

  // Utility functions:
  function clearCells()
  {
    $$("td[bandable]").each(function (data) {
      data.setStyle({
        background: "#99FF99"
    })});
  }

  function updateLabel(text)
  {
    var o = String.fromCharCode(60);
    var c = String.fromCharCode(62);
    var label = o + "label" + c;
    label += text;
    label += o + "/label" + c;
    $("label_div").firstDescendant().replace(label);
  };
</script>
<input onclick="doStuff()" type="button" value="Drag-Select Mode" />
<input onclick="doStuff2()" type="button" value="2-Click Mode" />

Note that the callback function is invoked with an array of the selected elements’ ids when the mouse has been released. I’ve hooked this up to change the element colours in the little script, but you could equally:

  function releaseCallback(selected)
  {
    new Ajax.Request('/some/form.php', { method: 'post',
                            parameters: {'ids[]':selected} });
  }

if you wanted to send the data back to a form somewhere.

This code is still a bit rough around the edges – YMMV. Props, as ever, to the good people at Prototype without whose magic this wouldn’t work.