define([], function() {

  'use strict';

  var Graph = mainevent.helpers.Graph;

  return Backbone.View.extend({

    /**
     * Object retrieved by fetchJobResult().
     */
    data: null,

    /**
     * Defined during render().
     */
    jqplotId: null,

    /**
     * Callback for window resize events.
     */
    resizeGraph: null,

    initialize: function(options) {
      this.options.dashArgs = options.dashArgs || {};

      mainevent.helpers.Event.on('DashboardArgsChange', this.onArgsChange, this);

      /**
       * Re-render the graph, in response to resize events, every 300ms at the most.
       */
      var view = this;
      this.resizeGraph = _.debounce(function() {
        view.render();
      }, 300),
      $(window).on('resize', view.resizeGraph);
    },

    onClose: function() {
      $(window).off('resize', this.resizeGraph);
      mainevent.helpers.Event.off('DashboardArgsChange', this.onArgsChange);
    },

    /**
     * Triggered by search/drop-down events in the parent Dashboard view.
     *
     * @param changed {Object} Pairs that have changed since the last event.
     * - Search events must be wrapped: {query: {k: v, ...}}.
     * - Non-search events: {k: v, ...}
     */
    onArgsChange: function(changed) {
      var view = this;

      // Change triggerd by search modal submit.
      if (changed.query) {
        // Replace dashboard settings with submitted args.
        view.options.dashArgs = changed.query;

        view.fetchGraphPoints(function() {
          view.render.call(view);
        });

        // Save a history point but don't trigger the router.
        var dashArgs = _.clone(view.options.dashArgs);
        view.navigate('dashboard', dashArgs, {trigger: false});

      } else {
        // Merge changed args with current.
        view.options.dashArgs = _.extend(view.options.dashArgs, changed);

        view.fetchGraphPoints(function() {
          view.render.call(view);
        });

        // Save a history point but don't trigger the router.
        var dashArgs = _.clone(view.options.dashArgs);
        dashArgs['dd'] = 1; // Indicate change came from drop-downs, not search.
        view.navigate('dashboard', dashArgs, {trigger: false});
      }
    },

    /**
     * Run the graph data job with an ad-hoc query, ex. total JSON events
     * between timestamp X and Y with the condition 'code > 200'.
     */
    fetchGraphPoints: function(callback) {
      var dashArgs = _.clone(this.options.dashArgs),
          date = mainevent.shared.Date,
          span = dashArgs['time-lte'] - dashArgs['time-gte'];

      dashArgs.partition = date.partitions[date.bestFitInterval(span)];

      var view = this,
          url = this.buildUrl(
            '/api/graph/CountAllPartitioned',
            dashArgs,
            false
          );

      $.ajax(
        url, {
          success: function(data) {
            view.data = data;
            data = null;
            callback();
          }
        }
      );
    },

    render: function() {
      // Use convention-based IDs so markup can just hold positional containers.
      this.jqplotId = this.el.id + '-canvas';

      var view = this;
          view.$el.empty();
          view.$el.append($('<div>').attr('id', view.jqplotId));

      var defaultAxes = {
        xaxis: {
          renderer: $.jqplot.DateAxisRenderer
        }
      };

      if (_.size(this.data)) {
        var graphData = [];
        _.each(this.data, function(result, time) {
          graphData.push([time, result.count]);
        });

        var axes = Graph.adjustAxes(view.$el, graphData, defaultAxes),
            title =
              mainevent.shared.Date.formatTime(parseInt(this.options.dashArgs['time-gte'], 10))
              + ' &mdash; ' +  mainevent.shared.Date.formatTime(parseInt(this.options.dashArgs['time-lte'], 10));
      } else {
        var axes = defaultAxes,
             graphData = [[0,0]],
             title = 'No events found.';
      }

      try {
        $.jqplot(
          view.jqplotId,
          [graphData],
          {
            title: title,
            axes: axes,
            series: [{lineWidth: 1}],
            highlighter: {
              show: true,
              sizeAdjust: 7.5,
            },
            cursor: {
              show: false
            }
          }
        );
      } catch (e) {
        if (e.message != 'No data to plot.') {
          console.log(e);
        }
      }
    }
  });
});

@@ -112,155 +112,8 @@
 (%7B%0A%0A
-    /**%0A     * Object retrieved by fetchJobResult().%0A     */%0A    data: null,%0A%0A    /**%0A     * Defined during render().%0A     */%0A    jqplotId: null,%0A%0A
     
@@ -1338,76 +1338,24 @@
 etch
-GraphPoints(function() %7B%0A          view.render.call(view);%0A        %7D
+AndRenderPoints(
 );%0A%0A
@@ -1692,76 +1692,24 @@
 etch
-GraphPoints(function() %7B%0A          view.render.call(view);%0A        %7D
+AndRenderPoints(
 );%0A%0A
@@ -2151,21 +2151,25 @@
    fetch
-Graph
+AndRender
 Points: 
@@ -2177,24 +2177,16 @@
 unction(
-callback
 ) %7B%0A    
@@ -2650,67 +2650,28 @@
 iew.
-data = data;%0A            data = null;%0A            callback(
+render(_.clone(data)
 );%0A 
@@ -2721,32 +2721,36 @@
 ender: function(
+data
 ) %7B%0A      // Use
@@ -2824,21 +2824,20 @@
 .%0A      
-this.
+var 
 jqplotId
@@ -2865,137 +2865,19 @@
 vas'
-;%0A%0A      var view = this;%0A          view.$el.empty();%0A          view.$el.append($('%3Cdiv%3E').attr('id', view.jqplotId));%0A%0A      var
+,%0A         
  def
@@ -2897,16 +2897,20 @@
         
+    
 xaxis: %7B
@@ -2906,24 +2906,28 @@
    xaxis: %7B%0A
+    
           re
@@ -2968,24 +2968,28 @@
         
+    
 %7D%0A      
 %7D;%0A%0A    
@@ -2980,20 +2980,137 @@
 %7D%0A      
+ 
+   
 %7D;%0A%0A
+      // Remove existing graph.%0A      this.$el.empty();%0A      this.$el.append($('%3Cdiv%3E').attr('id', jqplotId));%0A%0A
       if
@@ -3118,21 +3118,16 @@
 (_.size(
-this.
 data)) %7B
@@ -3170,21 +3170,16 @@
  _.each(
-this.
 data, fu
@@ -3298,20 +3298,20 @@
 ustAxes(
-view
+this
 .$el, gr
@@ -3734,21 +3734,16 @@
         
-view.
 jqplotId

Simplify graph fetch-render steps.