Add basic plotter for WebGL

There're still a bunch of TODOs. Will address those when we actually
have a need for this.

Change-Id: I137390d384967ffb618e0ecda37503e1e0df8301
diff --git a/build_tests/BUILD b/build_tests/BUILD
index 076e18c..a4c5829 100644
--- a/build_tests/BUILD
+++ b/build_tests/BUILD
@@ -26,6 +26,24 @@
     ],
 )
 
+emcc_binary(
+    name = "plotter.html",
+    srcs = ["webgl2_plot_test.cc"],
+    html_shell = "minimal_shell.html",
+    linkopts = [
+        "-s",
+        "USE_WEBGL2=1",
+        "-s",
+        "FULL_ES3=1",
+        "-s",
+        "TOTAL_MEMORY=" + repr(256 * 1024 * 1024),
+    ],
+    deps = [
+        "//frc971/analysis/plotting:webgl2_animator",
+        "//frc971/analysis/plotting:webgl2_plotter",
+    ],
+)
+
 cc_test(
     name = "gflags_build_test",
     size = "small",
diff --git a/build_tests/minimal_shell.html b/build_tests/minimal_shell.html
index 6158571..c9d2b86 100644
--- a/build_tests/minimal_shell.html
+++ b/build_tests/minimal_shell.html
@@ -56,7 +56,21 @@
     </div>
     <!--The width and height values in the canvas specify the pixel width/height for the WebGL canvas.
         The actual on-screen size is controlled by the stylesheet.-->
-    <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" width=3000 height=2000></canvas>
+    <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" width=1200 height=600></canvas>
+
+    <div>
+      General help information:<br>
+      <ul>
+        <li>Double-click to reset zoom.</li>
+        <li>Left-click to print mouse position (within plot) to console.</li>
+        <li>Ctrl-Z to undo zoom actions.</li>
+        <li>Right-click and drag to pan.</li>
+        <li>Left-click and drag zooms to the dragged area. If you press Escape while dragging, it will cancel the zoom.</li>
+        <li>Scroll up/down will zoom in and out.</li>
+        <li>Holding down "x" and "y" will restrict any
+            movement to the x and y axes respectively.</li>
+      </ul>
+    </div>
 
     <script type='text/javascript'>
       var statusElement = document.getElementById('status');
diff --git a/build_tests/webgl2_plot_test.cc b/build_tests/webgl2_plot_test.cc
new file mode 100644
index 0000000..2baefa9
--- /dev/null
+++ b/build_tests/webgl2_plot_test.cc
@@ -0,0 +1,35 @@
+#include <emscripten/emscripten.h>
+#include <emscripten/html5.h>
+
+#include <iostream>
+
+#include "frc971/analysis/plotting/webgl2_plotter.h"
+#include "frc971/analysis/plotting/webgl2_animator.h"
+
+float rand1() {
+  return static_cast<float>(rand()) / RAND_MAX;
+}
+
+int main() {
+  // Note that the animation_state must last until Redraw stops being called,
+  // which we cannot provide any bound on. As such, we don't currently destroy
+  // the memory until the webpage is closed.
+  frc971::plotting::Animator *animation_state =
+      new frc971::plotting::Animator("#canvas");
+  // Generate a bunch of lines with random y-values and evenly spaced x-values,
+  // such that each line takes up a set amount of space in the y-space. If
+  // that's unclear, then try running this and seeing what it looks like.
+  constexpr size_t kNLines = 30;
+  for (int jj = 0; jj < kNLines; ++jj) {
+    frc971::plotting::Line *line = animation_state->plotter()->AddLine();
+    // Randomly generate a color to use; each of r/g/b are between 0 and 1.
+    line->SetColor({.r = rand1(), .g = rand1(), .b = rand1()});
+    std::vector<Eigen::Vector2d> points;
+    constexpr size_t kNPoints = 100000;
+    for (int ii = 0; ii < kNPoints; ++ii) {
+      const float x = static_cast<float>(ii) / kNPoints;
+      points.emplace_back(x, std::sin(x + jj));
+    }
+    line->SetPoints(points);
+  }
+}