44

I was looking at this question and saw the reference to the iPhone game where you drag across the screen selecting letters as you go.

I was curious to see an implimentation of this in Javascript using tables. So you'd drag the mouse over each cell they would then become highlighted.

I'm not sure what the best method would be but I hope someone has a go. Someone attempted it here, but it doesn't really work.

alt text alt text

Thank Cacoo for the sexy diagrams. It's like an online visio, really nice. Check it out ;)

Community
  • 1
  • 1
Ben Shelock
  • 20,154
  • 26
  • 92
  • 125
  • 1
    Interesting challenge (and diagrams). The trick will be to prevent the default text selection in the browser... – tbeseda Jan 06 '10 at 15:29

3 Answers3

90

Here's a working prototype: http://jsfiddle.net/few5E/ Using jQuery for DOM hooking, but could easily be implemented with another framework.

Update: http://jsfiddle.net/Brv6J/ a slightly different version - the highlighted state will only change when you release and click again.

Update 2: http://jsfiddle.net/Brv6J/3/ - binding onselectstart so that text is not selected in IE.

A few relevant facts:

  • The mousedown event of the table cells is hooked to track the actual click. This event is stopped, so that text selection is hindered. Also binding ontextselect for the same effect in IE.
  • The mouseover event will toggle the highlighted class for the cell
  • The mouseout event is hooked on document. This is to ensure that it always runs. If the mouseup event was hooked on the table cell, it would not trigger if you released the mouse key with the mouse outside of the table. This state is tracked in isMouseDown.

Full source code for reference:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <title></title>
  <style type="text/css" media="screen">
    table td {
      width:100px;
      height:100px;
      text-align:center;
      vertical-align:middle;
      background-color:#ccc;
    }

    table td.highlighted {
      background-color:#999;
    }
  </style>
</head>
<body>
  <table cellpadding="0" cellspacing="1" id="our_table">
    <tr>
      <td>a</td>
      <td>b</td>
      <td>c</td>
    </tr>
    <tr>
      <td>d</td>
      <td>e</td>
      <td>f</td>
    </tr>
    <tr>
      <td>g</td>
      <td>h</td>
      <td>i</td>
    </tr>
  </table>

  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>
  <script type="text/javascript" charset="utf-8">
    $(function () {
      var isMouseDown = false;
      $("#our_table td")
        .mousedown(function () {
          isMouseDown = true;
          $(this).toggleClass("highlighted");
          return false; // prevent text selection
        })
        .mouseover(function () {
          if (isMouseDown) {
            $(this).toggleClass("highlighted");
          }
        })
        .bind("selectstart", function () {
          return false; // prevent text selection in IE
        });

      $(document)
        .mouseup(function () {
          isMouseDown = false;
        });
    });
  </script>
</body>
</html>
August Lilleaas
  • 54,010
  • 13
  • 102
  • 111
  • 2
    Interesting that you use toggleClass... in this case, when you hover back to a cell that's already selected, this removes the selection. This may or may not be correct based on application logic. Intuitively (and as I do in my solution), I keep all selected until mouseup. – Jaanus Jan 06 '10 at 15:58
  • 1
    See alternate link :) Just added it. – August Lilleaas Jan 06 '10 at 15:59
  • 1
    The use of toggleClass is just a hack, so to speak. In a proper unit testable implementation, you would use an instance with a boolean, or something like that. – August Lilleaas Jan 06 '10 at 16:01
  • 1
    Also, changing the state logic so that it will de-select everything on mouseup (that's what you describe, right?) is trivial. A `$("#our_table td").removeClass("highlighted")` on the mouseup event would be the appropriate hack in this case. – August Lilleaas Jan 06 '10 at 16:04
  • 2
    For those who want this to work on newly created Tables (via ajax), see this **[Fiddle](http://jsfiddle.net/Brv6J/803/)**: http://jsfiddle.net/Brv6J/803/ – MackieeE May 31 '13 at 09:48
  • None of Augusts solutions work anymore in Google Chrome from my point of view. Safari the same. But the solution posted by @MackieeE works for me. – Sven R. Oct 20 '15 at 10:59
  • any examples on how to implement this with touch support? – maco1717 Aug 24 '16 at 16:00
  • Shouldn't be too hard to hook up the events using http://hammerjs.github.io/ instead of the native "mousedown" events etc used here. – August Lilleaas Aug 26 '16 at 11:52
  • Any way to make this work for (vertically) long tables? If you add a couple more -s, the table/page doesn't automatically scroll down and select further down... – Yin Cognyto Oct 21 '17 at 23:09
  • add `if (event.button === 2) return false;` to disable right click from affecting selection at the beginning of the `mousedown` event and don't forget to add `event` as a parameter – ArcX Oct 21 '18 at 08:11
  • Holy hell what a nice tiny snippit of code to get this to work. Thanks. – Leeish Nov 30 '18 at 19:22
  • Not working properly if mouse pointer drags fast on the table row of small height. '27px' – Sowvik Roy Apr 07 '19 at 11:09
17

If you're after spreadsheet-like cell selection (in column/row blocks), you need to highlight every cell in every row that is between your start & end index (both row and cell) in your mouseover event:

for (var i = rowStart; i <= rowEnd; i++) {
    var rowCells = table.find("tr").eq(i).find("td");
    for (var j = cellStart; j <= cellEnd; j++) {
        rowCells.eq(j).addClass("selected");
    }        
}

As the user might start selecting cells from all directions (up-bottom, bottom-up, right-left, left-right) you need to assign the correct indexes for start & end.

Here is a jsFiddle.

Martin
  • 1,460
  • 1
  • 13
  • 17
  • Better, you'd use Dojo or jQuery (or something even higher-level) – paulsm4 Oct 16 '15 at 20:08
  • Add `table.find(".selected").removeClass("selected");` in the `mouseover` function to make it more spreadsheet-like i.e. deselect cells when moving over a selected area. Updated [fiddle](http://jsfiddle.net/chechs/qvw0pgcu/22/) – Slartibartfast Nov 20 '15 at 09:03
  • This is great, works with shift-selection. Would be amazing if it supported ctrl-selection as well. – Gigi Nov 17 '19 at 19:46
14

http://www.jaanuskase.com/stuff/dragSelect.html

Not sure if you wanted pure-Javascript implementation, I used jQuery for convenience.

Jaanus
  • 17,688
  • 15
  • 65
  • 110