Index: django_apps/running/static/week-total.js
===================================================================
--- django_apps/running/static/week-total.js	(revision 298)
+++ django_apps/running/static/week-total.js	(revision 298)
@@ -0,0 +1,48 @@
+function weekTotalGraph(myData, binder) {
+  Array.prototype.max = function () {
+      return Math.max.apply(Math, this);
+      };
+  
+  data = myData.data;
+  itemCount = data.length;
+  var  w = 1000,
+      h = 100,
+      x = pv.Scale.ordinal(pv.range(itemCount)).splitBanded(0, w, 4/5),
+      y = pv.Scale.linear(0, myData.data.max()).range(0, h);
+  
+  var vis = new pv.Panel().canvas(binder)
+      .width(w)
+      .height(h)
+      .bottom(20)
+      .left(20)
+      .right(5)
+      .top(5);
+  
+  var bar = vis.add(pv.Bar)
+      .data(data)
+      .left(function() x(this.index))
+      .width(x.range().band)
+      .bottom(0)
+      .height(y);
+  
+  bar.anchor("top").add(pv.Label)
+      .textStyle("white")
+      .text(function(d) d.toFixed(1));
+  
+  bar.anchor("bottom").add(pv.Label)
+      .textMargin(5)
+      .textBaseline("top")
+      .text(function() myData.label[this.index]);
+  
+  vis.add(pv.Rule)
+      .data(y.ticks())
+      .bottom(function(d) Math.round(y(d)) - .5)
+      .strokeStyle(function(d) d ? "rgba(255,255,255,.3)" : "#000")
+      .add(pv.Rule)
+      .left(0)
+      .width(5)
+      .strokeStyle("#000")
+      .anchor("left").add(pv.Label)
+  
+  vis.render();
+}
Index: django_apps/running/static/year-total.js
===================================================================
--- django_apps/running/static/year-total.js	(revision 298)
+++ django_apps/running/static/year-total.js	(revision 298)
@@ -0,0 +1,115 @@
+function yearTotalGraph(data, binder) {
+  var start = data[0].x;
+  var end = data[data.length - 1].x;
+  
+  /* Scales and sizing. */
+  var w = 810,
+      h1 = 300,
+      h2 = 30,
+      x = pv.Scale.linear(start, end).range(0, w),
+      y = pv.Scale.linear(0, pv.max(data, function(d) d.y)).range(0, h2);
+  
+  /* Interaction state. Focus scales will have domain set on-render. */
+  var i = {x:200, dx:100},
+      fx = pv.Scale.linear().range(0, w),
+      fy = pv.Scale.linear().range(0, h1);
+  
+  /* Root panel. */
+  var vis = new pv.Panel().canvas(binder)
+      .width(w)
+      .height(h1 + 20 + h2)
+      .bottom(20)
+      .left(30)
+      .right(20)
+      .top(5);
+  
+  /* Focus panel (zoomed in). */
+  var focus = vis.add(pv.Panel)
+      .def("init", function() {
+          var d1 = x.invert(i.x),
+              d2 = x.invert(i.x + i.dx),
+              dd = data.slice(
+                  Math.max(0, pv.search.index(data, d1, function(d) d.x) - 1),
+                  pv.search.index(data, d2, function(d) d.x) + 1);
+          fx.domain(d1, d2);
+          fy.domain(scale.checked ? [0, pv.max(dd, function(d) d.y)] : y.domain());
+          return dd;
+        })
+      .top(0)
+      .height(h1);
+  
+  /* X-axis ticks. */
+  focus.add(pv.Rule)
+      .data(function() fx.ticks())
+      .left(fx)
+      .strokeStyle("#eee")
+    .anchor("bottom").add(pv.Label)
+      .text(fx.tickFormat);
+  
+  /* Y-axis ticks. */
+  focus.add(pv.Rule)
+      .data(function() fy.ticks(7))
+      .bottom(fy)
+      .strokeStyle(function(d) d ? "#aaa" : "#000")
+    .anchor("left").add(pv.Label)
+      .text(fy.tickFormat);
+  
+  /* Focus area chart. */
+  focus.add(pv.Panel)
+      .overflow("hidden")
+    .add(pv.Area)
+      .data(function() focus.init())
+      .left(function(d) fx(d.x))
+      .bottom(1)
+      .height(function(d) fy(d.y))
+      .fillStyle("lightsteelblue")
+    .anchor("top").add(pv.Line)
+      .fillStyle(null)
+      .strokeStyle("steelblue")
+      .lineWidth(2);
+  
+  /* Context panel (zoomed out). */
+  var context = vis.add(pv.Panel)
+      .bottom(0)
+      .height(h2);
+  
+  /* X-axis ticks. */
+  context.add(pv.Rule)
+      .data(x.ticks())
+      .left(x)
+      .strokeStyle("#eee")
+    .anchor("bottom").add(pv.Label)
+      .text(x.tickFormat);
+  
+  /* Y-axis ticks. */
+  context.add(pv.Rule)
+      .bottom(0);
+  
+  /* Context area chart. */
+  context.add(pv.Area)
+      .data(data)
+      .left(function(d) x(d.x))
+      .bottom(1)
+      .height(function(d) y(d.y))
+      .fillStyle("lightsteelblue")
+    .anchor("top").add(pv.Line)
+      .strokeStyle("steelblue")
+      .lineWidth(2);
+  
+  /* The selectable, draggable focus region. */
+  context.add(pv.Panel)
+      .data([i])
+      .cursor("crosshair")
+      .events("all")
+      .event("mousedown", pv.Behavior.select())
+      .event("select", focus)
+    .add(pv.Bar)
+      .left(function(d) d.x)
+      .width(function(d) d.dx)
+      .fillStyle("rgba(255, 128, 128, .4)")
+      .cursor("move")
+      .event("mousedown", pv.Behavior.drag())
+      .event("drag", focus);
+  
+   vis.render();
+}
Index: django_apps/running/templates/user_index.html
===================================================================
--- django_apps/running/templates/user_index.html	(revision 294)
+++ django_apps/running/templates/user_index.html	(revision 298)
@@ -5,4 +5,6 @@
   <head>
      <script type="text/javascript" src="{{ STATIC_PREFIX }}protovis-r3.2.js"></script>
+     <script type="text/javascript" src="{{ STATIC_PREFIX }}week-total.js"></script>
+     <script type="text/javascript" src="{{ STATIC_PREFIX }}year-total.js"></script>
      <style type="text/css">
        #fig2 {
@@ -21,5 +23,5 @@
     <h1>Welcome {{ user }}</h1>
     <div id="center">
-      <h3>Week averages</h3>
+      <h3>Week totals</h3>
       <div id="fig2">
         <div id="week-statistics"> </div>
@@ -34,197 +36,63 @@
       </div>
     </div>
+    <form method="post" action="">
+    {% csrf_token %}
+    {{ formset.management_form }}
+    <table>
+    {% for form in formset %}
+      {% if forloop.first %}
+        <tr>
+        {% for field in form.visible_fields %}
+          <th>{{ field.label_tag }}</th>
+        {% endfor %}
+        </tr>
+      {% endif %}
+      <tr>
+      {% for field in form.visible_fields %}
+        {% if forloop.first %}
+          {% for hidden in form.hidden_fields %}
+            {{ hidden }}
+          {% endfor %}
+        {% endif %}
+
+       <td>{{ field.errors }}{{ field }}</td>
+      {% endfor %}
+      </tr>
+    {% endfor %}
+    </table>
+    <input type="submit" value="Submit Values"/>
+    </form>
     Beheer al je gegevens <a href="{% url admin:running_user_change user.id %}">hier</a>.
 
+
 <script type="text/javascript+protovis">
-
-// Get the required data
-var xhr = new XMLHttpRequest();
-xhr.open('GET', '{% url running.views.json_user_column user.id %}', false);
-xhr.send(null);
-var myData = JSON.parse(xhr.responseText, function (key, value) {
-    return value;
-});
-
-Array.prototype.max = function () {
-    return Math.max.apply(Math, this);
-    };
-
-data = myData.data;
-itemCount = data.length;
-var  w = 1000,
-    h = 100,
-    x = pv.Scale.ordinal(pv.range(itemCount)).splitBanded(0, w, 4/5),
-    y = pv.Scale.linear(0, myData.data.max()).range(0, h);
-
-var vis = new pv.Panel().canvas('week-statistics')
-    .width(w)
-    .height(h)
-    .bottom(20)
-    .left(20)
-    .right(5)
-    .top(5);
-
-var bar = vis.add(pv.Bar)
-    .data(data)
-    .left(function() x(this.index))
-    .width(x.range().band)
-    .bottom(0)
-    .height(y);
-
-bar.anchor("top").add(pv.Label)
-    .textStyle("white")
-    .text(function(d) d.toFixed(1));
-
-bar.anchor("bottom").add(pv.Label)
-    .textMargin(5)
-    .textBaseline("top")
-    .text(function() myData.label[this.index]);
-
-vis.add(pv.Rule)
-    .data(y.ticks())
-    .bottom(function(d) Math.round(y(d)) - .5)
-    .strokeStyle(function(d) d ? "rgba(255,255,255,.3)" : "#000")
-    .add(pv.Rule)
-    .left(0)
-    .width(5)
-    .strokeStyle("#000")
-    .anchor("left").add(pv.Label)
-
-vis.render();
-
+  // Graph Week totals
+  var xhr = new XMLHttpRequest();
+  xhr.open('GET', '{% url running.views.json_user_column user.id %}', false);
+  xhr.send(null);
+  var myData = JSON.parse(xhr.responseText, function (key, value) {
+      return value;
+  });
+  weekTotalGraph(myData, 'week-statistics');
 </script>
 
 
 <script type="text/javascript+protovis">
-// Get the required data
-var xhr = new XMLHttpRequest();
-xhr.open('GET', '{% url running.views.json_user_total user.id %}', false);
-xhr.send(null);
-
-var data = JSON.parse(xhr.responseText, function (key, value) {
-    var type;
-    if ( value != null) {
-      if ( key === 'x') {
-         return new Date(value);
+  // Graph Year totals
+  var xhr = new XMLHttpRequest();
+  xhr.open('GET', '{% url running.views.json_user_total user.id %}', false);
+  xhr.send(null);
+  
+  var data = JSON.parse(xhr.responseText, function (key, value) {
+      var type;
+      if ( value != null) {
+        if ( key === 'x') {
+           return new Date(value);
+        }
       }
-    }
-    return value;
-});
-
-var start = data[0].x;
-var end = data[data.length - 1].x;
-
-/* Scales and sizing. */
-var w = 810,
-    h1 = 300,
-    h2 = 30,
-    x = pv.Scale.linear(start, end).range(0, w),
-    y = pv.Scale.linear(0, pv.max(data, function(d) d.y)).range(0, h2);
-
-/* Interaction state. Focus scales will have domain set on-render. */
-var i = {x:200, dx:100},
-    fx = pv.Scale.linear().range(0, w),
-    fy = pv.Scale.linear().range(0, h1);
-
-/* Root panel. */
-var vis = new pv.Panel().canvas('total-statistics')
-    .width(w)
-    .height(h1 + 20 + h2)
-    .bottom(20)
-    .left(30)
-    .right(20)
-    .top(5);
-
-/* Focus panel (zoomed in). */
-var focus = vis.add(pv.Panel)
-    .def("init", function() {
-        var d1 = x.invert(i.x),
-            d2 = x.invert(i.x + i.dx),
-            dd = data.slice(
-                Math.max(0, pv.search.index(data, d1, function(d) d.x) - 1),
-                pv.search.index(data, d2, function(d) d.x) + 1);
-        fx.domain(d1, d2);
-        fy.domain(scale.checked ? [0, pv.max(dd, function(d) d.y)] : y.domain());
-        return dd;
-      })
-    .top(0)
-    .height(h1);
-
-/* X-axis ticks. */
-focus.add(pv.Rule)
-    .data(function() fx.ticks())
-    .left(fx)
-    .strokeStyle("#eee")
-  .anchor("bottom").add(pv.Label)
-    .text(fx.tickFormat);
-
-/* Y-axis ticks. */
-focus.add(pv.Rule)
-    .data(function() fy.ticks(7))
-    .bottom(fy)
-    .strokeStyle(function(d) d ? "#aaa" : "#000")
-  .anchor("left").add(pv.Label)
-    .text(fy.tickFormat);
-
-/* Focus area chart. */
-focus.add(pv.Panel)
-    .overflow("hidden")
-  .add(pv.Area)
-    .data(function() focus.init())
-    .left(function(d) fx(d.x))
-    .bottom(1)
-    .height(function(d) fy(d.y))
-    .fillStyle("lightsteelblue")
-  .anchor("top").add(pv.Line)
-    .fillStyle(null)
-    .strokeStyle("steelblue")
-    .lineWidth(2);
-
-/* Context panel (zoomed out). */
-var context = vis.add(pv.Panel)
-    .bottom(0)
-    .height(h2);
-
-/* X-axis ticks. */
-context.add(pv.Rule)
-    .data(x.ticks())
-    .left(x)
-    .strokeStyle("#eee")
-  .anchor("bottom").add(pv.Label)
-    .text(x.tickFormat);
-
-/* Y-axis ticks. */
-context.add(pv.Rule)
-    .bottom(0);
-
-/* Context area chart. */
-context.add(pv.Area)
-    .data(data)
-    .left(function(d) x(d.x))
-    .bottom(1)
-    .height(function(d) y(d.y))
-    .fillStyle("lightsteelblue")
-  .anchor("top").add(pv.Line)
-    .strokeStyle("steelblue")
-    .lineWidth(2);
-
-/* The selectable, draggable focus region. */
-context.add(pv.Panel)
-    .data([i])
-    .cursor("crosshair")
-    .events("all")
-    .event("mousedown", pv.Behavior.select())
-    .event("select", focus)
-  .add(pv.Bar)
-    .left(function(d) d.x)
-    .width(function(d) d.dx)
-    .fillStyle("rgba(255, 128, 128, .4)")
-    .cursor("move")
-    .event("mousedown", pv.Behavior.drag())
-    .event("drag", focus);
-
- vis.render();
-
-    </script>
+      return value;
+  });
+  yearTotalGraph(data, 'total-statistics');
+</script>
   </body>
 </html>
Index: django_apps/running/views.py
===================================================================
--- django_apps/running/views.py	(revision 294)
+++ django_apps/running/views.py	(revision 298)
@@ -3,4 +3,7 @@
 from django.core import serializers
 from django.http import HttpResponse
+from django.forms.models import modelformset_factory, inlineformset_factory
+from django.template import RequestContext
+
 from django.shortcuts import render_to_response, get_object_or_404
 from running.models import Result, User
@@ -9,5 +12,16 @@
 def user_index(request, user_name):
     user = get_object_or_404(User, name=user_name)
-    return render_to_response('user_index.html', { 'user' : user })
+    ResultFormSet = modelformset_factory(Result, fields=('date', 'distance', 'time'), exclude=('user'), extra=3, can_delete=True)
+    if request.method == 'POST':
+       formset = ResultFormSet(request.POST, request.FILES)
+       if formset.is_valid():
+         instances = formset.save(commit=False)
+         for instance in instances:
+           instance.user = user
+           instance.save()
+
+    result_list = Result.objects.filter(user=user)
+    formset = ResultFormSet(queryset=result_list)
+    return render_to_response('user_index.html', { 'user' : user, 'formset' : formset }, context_instance=RequestContext(request))
 
 def index(request):
@@ -38,7 +52,9 @@
     result_list = Result.objects.values_list('date', 'distance')
     json_list = []
+    distance_total = 0.0
     # Output date object in epoch milliseconds as JavaScript find this easy to use.
     for (date,distance) in result_list:
-        json_list.append({'x': int(date.strftime("%s")) * 1000, 'y' : float(distance)})
+        distance_total += float(distance)
+        json_list.append({'x': int(date.strftime("%s")) * 1000, 'y' : distance_total})
     data = json.dumps(json_list, ensure_ascii=False, indent=2)
     return HttpResponse(data,mimetype="application/json")
