Use CSS to size plots instead of absolute position

This will make things a lot easier to resize and track.  Absolute
positions are tough on other elements.  Have the plot fill the whole
containing element.

Change-Id: I9463c86a723e257bf8c9b083b1a8dcc31a544604
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
Signed-off-by: James Kuszmaul <jabukuszmaul@gmail.com>
diff --git a/aos/network/www/aos_plotter.ts b/aos/network/www/aos_plotter.ts
index 270c0d9..0145c07 100644
--- a/aos/network/www/aos_plotter.ts
+++ b/aos/network/www/aos_plotter.ts
@@ -190,7 +190,6 @@
 
   private plots: AosPlot[] = [];
   private messages = new Set<MessageHandler>();
-  private lowestHeight = 0;
   constructor(private readonly connection: Connection) {
     // Set up to redraw at some regular interval. The exact rate is unimportant.
     setInterval(() => {
@@ -223,24 +222,19 @@
   // Add a new figure at the provided position with the provided size within
   // parentElement.
   addPlot(
-      parentElement: Element, topLeft: number[]|null = null,
+      parentElement: Element,
       size: number[] = [AosPlotter.DEFAULT_WIDTH, AosPlotter.DEFAULT_HEIGHT]):
       AosPlot {
-    if (topLeft === null) {
-      topLeft = [0, this.lowestHeight];
-    }
     const div = document.createElement("div");
-    div.style.top = topLeft[1].toString();
-    div.style.left = topLeft[0].toString();
-    div.style.position = 'absolute';
+    div.style.position = 'relative';
+    div.style.width = size[0].toString() + "px";
+    div.style.height = size[1].toString() + "px";
     parentElement.appendChild(div);
-    const newPlot = new Plot(div, size[0], size[1]);
+    const newPlot = new Plot(div);
     for (let plot of this.plots.values()) {
       newPlot.linkXAxis(plot.plot);
     }
     this.plots.push(new AosPlot(this, newPlot));
-    // Height goes up as you go down.
-    this.lowestHeight = Math.max(topLeft[1] + size[1], this.lowestHeight);
     return this.plots[this.plots.length - 1];
   }
   private draw(): void {
diff --git a/aos/network/www/colors.ts b/aos/network/www/colors.ts
index b173e13..5c5dd86 100644
--- a/aos/network/www/colors.ts
+++ b/aos/network/www/colors.ts
@@ -1,4 +1,6 @@
 export const RED: number[] = [1, 0, 0];
+export const ORANGE: number[] = [1, 0.65, 0];
+export const YELLOW: number[] = [1, 1, 0];
 export const GREEN: number[] = [0, 1, 0];
 export const BLUE: number[] = [0, 0, 1];
 export const BROWN: number[] = [0.6, 0.3, 0];
diff --git a/aos/network/www/demo_plot.ts b/aos/network/www/demo_plot.ts
index cbd133a..ecd4da6 100644
--- a/aos/network/www/demo_plot.ts
+++ b/aos/network/www/demo_plot.ts
@@ -23,12 +23,12 @@
   const height = AosPlotter.DEFAULT_HEIGHT;
 
   const benchmarkDiv = document.createElement('div');
-  benchmarkDiv.style.top = (height * 2).toString();
-  benchmarkDiv.style.left = '0';
-  benchmarkDiv.style.position = 'absolute';
+  benchmarkDiv.style.width = width.toString() + "px";
+  benchmarkDiv.style.height = height.toString() + "px";
+  benchmarkDiv.style.position = 'relative';
   parentDiv.appendChild(benchmarkDiv);
 
-  const benchmarkPlot = new Plot(benchmarkDiv, width, height);
+  const benchmarkPlot = new Plot(benchmarkDiv);
 
   const aosPlotter = new AosPlotter(conn);
 
diff --git a/aos/network/www/plotter.ts b/aos/network/www/plotter.ts
index e56a808..842f1b7 100644
--- a/aos/network/www/plotter.ts
+++ b/aos/network/www/plotter.ts
@@ -409,7 +409,7 @@
 
   public static readonly COLOR_CYCLE = [
     Colors.RED, Colors.GREEN, Colors.BLUE, Colors.BROWN, Colors.PINK,
-    Colors.CYAN, Colors.WHITE
+    Colors.CYAN, Colors.WHITE, Colors.ORANGE, Colors.YELLOW
   ];
   private colorCycleIndex = 0;
 
@@ -850,6 +850,7 @@
 export class Plot {
   private canvas = document.createElement('canvas');
   private textCanvas = document.createElement('canvas');
+  private lineDrawerContext: WebGLRenderingContext;
   private drawer: LineDrawer;
   private static keysPressed:
       object = {'x': false, 'y': false, 'Escape': false};
@@ -869,25 +870,26 @@
   private defaultYRange: number[]|null = null;
   private zoomRectangle: Line;
 
-  constructor(wrapperDiv: HTMLDivElement, width: number, height: number) {
+  constructor(wrapperDiv: HTMLDivElement) {
     wrapperDiv.appendChild(this.canvas);
     wrapperDiv.appendChild(this.textCanvas);
     this.lastTimeMs = (new Date()).getTime();
 
-    this.canvas.width =
-        width - this.axisLabelBuffer.left - this.axisLabelBuffer.right;
-    this.canvas.height =
-        height - this.axisLabelBuffer.top - this.axisLabelBuffer.bottom;
-    this.canvas.style.left = this.axisLabelBuffer.left.toString();
-    this.canvas.style.top = this.axisLabelBuffer.top.toString();
-    this.canvas.style.position = 'absolute';
-    this.drawer = new LineDrawer(this.canvas.getContext('webgl'));
+    this.canvas.style.paddingLeft = this.axisLabelBuffer.left.toString() + "px";
+    this.canvas.style.paddingRight = this.axisLabelBuffer.right.toString() + "px";
+    this.canvas.style.paddingTop = this.axisLabelBuffer.top.toString() + "px";
+    this.canvas.style.paddingBottom = this.axisLabelBuffer.bottom.toString() + "px";
+    this.canvas.style.width = "100%";
+    this.canvas.style.height = "100%";
+    this.canvas.style.boxSizing = "border-box";
 
-    this.textCanvas.width = width;
-    this.textCanvas.height = height;
-    this.textCanvas.style.left = '0';
-    this.textCanvas.style.top = '0';
+    this.canvas.style.position = 'absolute';
+    this.lineDrawerContext = this.canvas.getContext('webgl');
+    this.drawer = new LineDrawer(this.lineDrawerContext);
+
     this.textCanvas.style.position = 'absolute';
+    this.textCanvas.style.width = "100%";
+    this.textCanvas.style.height = "100%";
     this.textCanvas.style.pointerEvents = 'none';
 
     this.canvas.addEventListener('dblclick', (e) => {
@@ -934,9 +936,22 @@
   }
 
   mouseCanvasLocation(event: MouseEvent): number[] {
+    const computedStyle = window.getComputedStyle(this.canvas);
+    const paddingLeftStr = computedStyle.getPropertyValue('padding-left');
+    const paddingTopStr = computedStyle.getPropertyValue('padding-top');
+    if (paddingLeftStr.substring(paddingLeftStr.length - 2) != "px") {
+      throw new Error("Left padding should be specified in pixels.");
+    }
+    if (paddingTopStr.substring(paddingTopStr.length - 2) != "px") {
+      throw new Error("Left padding should be specified in pixels.");
+    }
+    // Javascript will just ignore the extra "px".
+    const paddingLeft = Number.parseInt(paddingLeftStr);
+    const paddingTop = Number.parseInt(paddingTopStr);
+
     return [
-      event.offsetX * 2.0 / this.canvas.width - 1.0,
-      -event.offsetY * 2.0 / this.canvas.height + 1.0
+      (event.offsetX - paddingLeft) * 2.0 / this.canvas.width - 1.0,
+      -(event.offsetY - paddingTop) * 2.0 / this.canvas.height + 1.0
     ];
   }
 
@@ -1154,6 +1169,17 @@
     const curTime = (new Date()).getTime();
     const frameRate = 1000.0 / (curTime - this.lastTimeMs);
     this.lastTimeMs = curTime;
+    const parentWidth = this.textCanvas.parentElement.offsetWidth;
+    const parentHeight = this.textCanvas.parentElement.offsetHeight;
+    this.textCanvas.width = parentWidth;
+    this.textCanvas.height = parentHeight;
+    this.canvas.width =
+        parentWidth - this.axisLabelBuffer.left - this.axisLabelBuffer.right;
+    this.canvas.height =
+        parentHeight - this.axisLabelBuffer.top - this.axisLabelBuffer.bottom;
+    this.lineDrawerContext.viewport(
+        0, 0, this.lineDrawerContext.drawingBufferWidth,
+        this.lineDrawerContext.drawingBufferHeight);
 
     // Clear the overlay.
     const textCtx = this.textCanvas.getContext("2d");