var d3 = require('d3');

function Simulation(opts) {
  var self = this;
  if (!(self instanceof Simulation)) {
    return new Simulation(opts);
  }

  self.domainMin = opts.domainMin || -5;
  self.domainMax = opts.domainMin || 5;
  Simulation.prototype.renderFrame = opts.renderFrame;

  var viewSelector = opts.selection || "#simulation";
  self.viewContainer = d3.select(viewSelector).node();

  self.stopped = false;
  self.d3canvas = d3.select(viewSelector + " canvas")
    .on('click', function () {
      self.stopped = !self.stopped;
      if (!self.stopped)
          self.run();
    });

  self.canvas = self.d3canvas.node();
  self.ctx = self.canvas.getContext("2d");
}

exports.Simulation = Simulation;

Simulation.prototype.clearCanvas = function() {
  var self = this;
  self.ctx.clearRect(0, 0, self.width, self.height);
}

Simulation.prototype.run = function() {
  var self = this;
  d3.timer(function doOneFrame(elapsed) {
    // this.t -> absolute time in millis when this timer was started
    // elapsed -> the number of milliseconds since this timer started.
    // this.t + elapsedTime -> now
    self.updateView();
    self.clearCanvas();
    self.renderFrame();
    return self.stopped;
  });
};

Simulation.prototype.updateView = function() {
  var self = this;

  // Get the dimensions of the DOM element containing our canvas, e.g. the div#simulation,
  // and ensure the canvas has the same dimensions. We do this every frame, since it
  // seems to have trivial cost and allows seamless resizing.
  var width = self.viewContainer.clientWidth;
  var height = self.viewContainer.clientHeight;

  if (width!==self.width || height!=self.height) {
    self.width = width;
    self.height = height;
    self.d3canvas
      .attr("width", width)
      .attr("height", height);

    // We'll scale such that height is always the full range [domainMin..domainMax]
    // Width will be same resolution.
    // TODO: provide option to fix width to full range instead of height.
    var pixelsPerUnit = height / (self.domainMax - self.domainMin);

    self.x = d3.scale.linear()
      .domain([0, 1])
      .range([width/2, pixelsPerUnit + width/2]);

    self.y = d3.scale.linear()
      .domain([self.domainMin, self.domainMax])
      .range([height, 0]);
  }
};



@@ -18,16 +18,127 @@
 'd3');%0A%0A
+function defaultInitializeModel() %7B%7D%0Afunction defaultUpdateModel(elapsed) %7B%7D%0Afunction defaultRenderFrame() %7B%7D%0A%0A
 function
@@ -334,16 +334,182 @@
 n %7C%7C 5;%0A
+  Simulation.prototype.initializeModel = opts.initializeModel %7C%7C defaultInitializeModel;%0A  Simulation.prototype.updateModel = opts.updateModel %7C%7C defaultUpdateModel;%0A
   Simula
@@ -553,16 +553,38 @@
 derFrame
+ %7C%7C defaultRenderFrame
 ;%0A%0A  var
@@ -684,24 +684,185 @@
 r).node();%0A%0A
+  // Create an in memory only element of type 'custom'%0A  self.modelContainer = document.createElement(%22custom%22);%0A  self.model = d3.select(self.modelContainer);%0A%0A
   self.stopp
@@ -1131,16 +1131,35 @@
 (%222d%22);%0A
+  self.frames = 0;%0A
 %7D%0A%0Aexpor
@@ -1187,16 +1187,190 @@
 ation;%0A%0A
+Simulation.prototype.initializeModel = defaultInitializeModel;%0ASimulation.prototype.updateModel = defaultUpdateModel;%0ASimulation.prototype.renderFrame = defaultRenderFrame;%0A%0A
 Simulati
@@ -1543,16 +1543,42 @@
 = this;%0A
+  self.initializeModel();%0A
   d3.tim
@@ -1786,16 +1786,74 @@
  -%3E now%0A
+    self.updateModel(elapsed);%0A    if (!self.stopped) %7B%0A  
     self
@@ -1863,24 +1863,26 @@
 dateView();%0A
+  
     self.cle
@@ -1889,24 +1889,26 @@
 arCanvas();%0A
+  
     self.ren
@@ -1915,24 +1915,51 @@
 derFrame();%0A
+      ++self.frames;%0A    %7D%0A
     return s

Add methods for data model.