Wijmo 5 - Event Debouncing

Shows how to debounce Wijmo events so they don't fire too often.

HTML

<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="http://cdn.wijmo.com/5.latest/styles/wijmo.min.css">
<script src="http://cdn.wijmo.com/5.latest/controls/wijmo.min.js"></script>
<script src="http://cdn.wijmo.com/5.latest/controls/wijmo.input.min.js"></script>
<script src="http://cdn.wijmo.com/5.latest/controls/wijmo.grid.min.js"></script>
<script src="http://cdn.wijmo.com/5.latest/controls/wijmo.chart.min.js"></script>
<script src="http://cdn.wijmo.com/5.latest/controls/wijmo.gauge.min.js"></script>
<script src="http://cdn.wijmo.com/5.latest/interop/angular/wijmo.angular.min.js"></script>
<div class="container" ng-app="app" ng-controller="appCtrl">

  <h1>Event Debouncing</h1>

  <p>
    When handling events that fire in bursts, like mouse moves, 
    key presses, or selection changes, you may be able to improve application 
    performance by "debouncing" the event (handing it only a little while after 
    it stops firing).</p>
  <p>
    For example, this <b>FlexGrid</b> control handles the <b>selectionChanging</b> 
    and <b>mousemove</b> events synchronously (without debouncing). The event
    handler calls a "sleep" method to simulate a lengthy operation.</p>

  <wj-flex-grid style="max-height:150px" items-source="data" initialized="initRegular(s,e)">
  </wj-flex-grid>

  <p>
    And this <b>FlexGrid</b> control handles the <b>selectionChanging</b> and <b>mousemove</b>
    events using the same handlers, but this time with a 500ms debounce.</p>

  <wj-flex-grid 
    items-source="data"
    initialized="initDebounced(s,e)">
  </wj-flex-grid>

  <p>
    The log elements below show how the <b>selectionChanging</b> and <b>mousemove</b> events 
    get handled. For the top grid, the logs are updated immediately after each selection change
    and mouse move. For the bottom grid, they are updated 500ms after the events stop firing.</p>

  <div id="logsel" class="log">
    selection...

CSS

.wj-flexgrid {
  max-height: 150px;
}

.wj-radialgauge {
  width: 300px;
  margin: auto auto;
}

.log {
  font-size: 150%;
  color: #800000;
  text-align: center;
}

p {
  margin-top: 12px;
}

JavaScript

var app = angular.module('app', ['wj']);
app.controller('appCtrl', function($scope) {

  // attach Wijmo and DOM event handlers without debouncing
  $scope.initRegular = function(s, e) {
    s.selectionChanging.addHandler(selectionChanging, this); // Wijmo event
    s.addEventListener(s.hostElement, 'mousemove', mouseMove); // DOM event
  };

  // attach Wijmo and DOM event handlers with debouncing
  $scope.initDebounced = function(s, e) {
    s.selectionChanging.addHandler(debounce(selectionChanging, 500), this); // Wijmo event
    s.addEventListener(s.hostElement, 'mousemove', debounce(mouseMove, 500)); // DOM event
  };
  
  // handle gauge's valuechanged event
  $scope.valueChangedDebounced = debounce(function(s, e) {
    	$scope.theGaugeValue = s.value;
      $scope.$apply();
	}, 300);

  // Wijmo event handler
  function selectionChanging(s, e) {
    var sel = e.range;
    log('logsel', 'Selection Changing to (' + sel.row + ', ' + sel.col + ')');
    sleep(100); // simulate an expensive handler
  }

  // DOM event handler
  function mouseMove(e) {
    log('logmove', 'Mouse Moved to (' + Math.round(e.pageX) + ', ' + Math.round(e.pageY) + ')');
    sleep(100); // simulate an expensive handler
  }

  // log events
  function log(id, msg) {
    document.getElementById(id).textContent = msg;
  }
 
  // simulate expensive event handling
  function sleep(milliseconds) {
    var start = Date.now();
    for (;;) {
      if (Date.now() - start > milliseconds) {
        break;
    }
  }
}  

  // create some data
  var items = 'Apple,Apricot,Banana,Blueberry,Cherry,Coconut,Grape'.split(',');
  $scope.data = [];
  for (var i = 0; i < 100; i++) {
    $scope.data.push({
      id: i,
      fruit: items[i % items.length],
      qty: i % 12,
      check: (i % 3 == 0)
    });
  }
});

/**
 * Returns a function that calls another function after being
 * called at least once and then not called again for a specified
 * interval.
 *
 * This can be used when implementing some...