Generate the SVG graph server-side instead of on the client.
authorBenjamin Smedberg <benjamin@smedbergs.us>
Mon, 05 Jan 2009 13:27:03 -0500
changeset 11 240e28622925
parent 10 80fc943e21cf
child 12 0b5a89ccda6a
push id6
push userbsmedberg@mozilla.com
push date2009-01-05 19:05 +0000
Generate the SVG graph server-side instead of on the client.
warning-ui/index.html
warning-ui/static/warnings.css
--- a/warning-ui/index.html
+++ b/warning-ui/index.html
@@ -1,107 +1,69 @@
+<?python
+kHeight = 200
+kIndent = 40
+kPadding = 5
+kSpacing = 6
+
+minw = min( (unique for buildnumber, rev, unique in builds) )
+maxw = max( (unique for buildnumber, rev, unique in builds) )
+
+yscale = (kHeight - kPadding * 2) / float(maxw - minw)
+
+graphWidth = (len(builds) + 1) * kSpacing
+totalWidth = graphWidth + kIndent * 2
+
+def converty(y):
+   return kHeight - kPadding - ((y - minw) * yscale)
+
+def convertx(x):
+   return kIndent + kSpacing * (len(builds) - x)
+?>
+
 <html xmlns="http://www.w3.org/1999/xhtml"
       xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:xlink="http://www.w3.org/1999/xlink"
       xmlns:py="http://genshi.edgewall.org/">
   <xi:include href="common.inc" />
 
   <head>
     <title>Warnings</title>
   </head>
   <body class="index">
-    <svg xmlns="http://www.w3.org/2000/svg" id="graph" preserveAspectRatio="none"
-         width="500" height="200" style="border: 1px solid black;" />
+    <div id="graphscroller">
+    <svg xmlns="http://www.w3.org/2000/svg" id="graph"
+         width="${totalWidth}" height="${kHeight}"
+         style="border: 1px solid black; position: relative: right: 0%;">
+
+
+      <py:for each="i in xrange(minw - minw % 25, maxw, 25)">
+        <line class="scale" x1="${kIndent}" x2="${graphWidth + kIndent}"
+              y1="${converty(i)}" y2="${converty(i)}" />
+        <text class="scaleText" x="${kIndent - 2}" y="${converty(i)}">${i}</text>
+        <text class="scaleText right" x="${graphWidth + kIndent + 2}" y="${converty(i)}">${i}</text>
+      </py:for>
+      
+      <polyline id="gline"
+                points="${' '.join( ('%f %f' % (convertx(i), converty(builds[i][2]))
+                                                for i in xrange(0, len(builds))) )}" />
+
+      <py:for each="i in xrange(0, len(builds))">
+        <a py:with="buildnumber, rev, unique = builds[i]"
+           xlink:href="/build?id=${buildnumber}">
+          <text class="overlay"
+                x="50%"
+                y="20">Warnings: ${unique}</text>
+          <text class="overlay"
+                x="50%"
+                y="40">Rev: ${rev}</text>
+          <circle class="mark"
+                  cx="${convertx(i)}" cy="${converty(unique)}" r="${kSpacing / 2}" />
+        </a>
+      </py:for>
+    </svg>
+    </div>
     
     <ul>
       <li py:for="buildnumber, rev, unique in builds"><a href="build?id=${buildnumber}">${rev}</a></li>
     </ul>
-
-    <script type="application/x-javascript">
-      var kWidth, kHeight, min, max, g, i, x, y, s, points, txt, a, hit, gline;
-
-      kWidth = 500;
-      kHeight = 200;
-
-      gData = [
-      <py:for each="buildnumber, rev, unique in builds">
-        [${buildnumber}, "${rev}", ${unique}],
-      </py:for>
-      ];
-
-      // Oh, my kingdom for a .reduce, but I want this to work in Safari
-      min = null;
-      max = null;
-      for (i = 0; i &lt; gData.length; ++i) {
-        if (min == null || gData[i][2] &lt; min)
-          min = gData[i][2];
-        if (max == null || gData[i][2] &gt; max)
-          max = gData[i][2];
-      }
-
-      g = document.getElementById("graph");
-
-      for (i = min - min % 25; i &lt; max; i += 25) {
-        y = kHeight - ((i - min) / (max - min) * (kHeight - 10)) - 5;
-        s = document.createElementNS('http://www.w3.org/2000/svg', 'line');
-        s.setAttribute('class', 'scale');
-        s.x1.baseVal.value = 40;
-        s.x2.baseVal.value = 490;
-        s.y1.baseVal.value = y;
-        s.y2.baseVal.value = y;
-        g.appendChild(s);
-
-        s = document.createElementNS('http://www.w3.org/2000/svg', 'text');
-        s.setAttribute('class', 'scaleText');
-        s.textContent = i;
-        s.setAttribute('x', 38);
-        s.setAttribute('y', y);
-        g.appendChild(s);
-      }
-
-      points = [];
-
-      for (i = gData.length - 1; i &gt;= 0; --i) {
-        id = gData[i][0];
-        rev = gData[i][1];
-        t = gData[i][2];
-
-        a = document.createElementNS('http://www.w3.org/2000/svg', 'a');
-        a.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '/build?id=' + id);
-        g.appendChild(a);
-
-        txt = document.createElementNS('http://www.w3.org/2000/svg', 'text');
-        txt.setAttribute('class', 'overlay');
-        txt.textContent = "Warnings: " + t;
-        txt.setAttribute('x', kWidth / 2);
-        txt.setAttribute('y', 20);
-        a.appendChild(txt);
-
-        txt = document.createElementNS('http://www.w3.org/2000/svg', 'text');
-        txt.setAttribute('class', 'overlay');
-        txt.textContent = 'Rev: ' + rev;
-        txt.setAttribute('x', kWidth / 2);
-        txt.setAttribute('y', 40);
-        a.appendChild(txt);
-        
-        x = (gData.length - i) / gData.length * (kWidth - 50) + 40;
-        y = kHeight - ((t - min) / (max - min) * (kHeight - 10)) - 5;
-
-        points.push(x, y);
-
-        if (isNaN(y))
-          throw new Error("isNaN: " + [i, t, x, y, max, min]);
-
-        hit = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
-        hit.setAttribute('class', 'mark');
-        hit.cx.baseVal.value = x;
-        hit.cy.baseVal.value = y;
-        hit.r.baseVal.value = 3;
-        a.appendChild(hit);
-      }
-
-      gline = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
-      gline.setAttribute('id', 'gline');
-      gline.setAttribute('points', points.join(' '));
-
-      g.insertBefore(gline, g.childNodes[0]);
-    </script>
   </body>
 </html>
--- a/warning-ui/static/warnings.css
+++ b/warning-ui/static/warnings.css
@@ -48,16 +48,22 @@ a:hover .overlay {
 }
 .scaleText {
   font-family: sans-serif;
   font-size: 12px;
   fill: #666;
   text-anchor: end;
   dominant-baseline: middle;
 }
+.scaleText.right {
+  text-anchor: start;
+}
 
 .header {
   background-color: rgb(250, 160, 20);
   color: black;
   font-size: 150%;
   padding: 5px;
   margin-bottom: 1em;
 }
+#graphscroller {
+    overflow-x: auto;
+}
\ No newline at end of file