Implement Track Registry

Implements a track registry so the track implementation can be loaded
dynamically. Adds barebones implementation of two track types
(CpuSliceTrack and CpuCounterTrack) for demoing the registry.

The track implementation is currently represented by TrackImpl class,
which can only draw on canvas using the draw() method. How a track will
implement DOM is still TBD and out of the scope for this CL.


Bug:111540363

Change-Id: I0489f161c3783af6d54568fe839301f47ae0291a
diff --git a/ui/src/frontend/track.ts b/ui/src/frontend/track.ts
index 1e1441f..fabb954 100644
--- a/ui/src/frontend/track.ts
+++ b/ui/src/frontend/track.ts
@@ -14,38 +14,30 @@
 
 import * as m from 'mithril';
 
-import {GridlineHelper} from './gridline_helper';
+import {TrackState} from '../common/state';
+
 import {Milliseconds, TimeScale} from './time_scale';
+import {TrackImpl} from './track_impl';
+import {trackRegistry} from './track_registry';
 import {TrackShell} from './track_shell';
 import {VirtualCanvasContext} from './virtual_canvas_context';
 
 export const Track = {
+  oninit({attrs}) {
+    // TODO: Since ES6 modules are asynchronous and it is conceivable that we
+    // want to load a track implementation on demand, we should not rely here on
+    // the fact that the track is already registered. We should show some
+    // default content until a track implementation is found.
+    const trackCreator = trackRegistry.getCreator(attrs.trackState.type);
+    this.trackImpl = trackCreator.create(attrs.trackState);
+  },
+
   view({attrs}) {
     const sliceStart: Milliseconds = 100000;
     const sliceEnd: Milliseconds = 400000;
 
     const rectStart = attrs.timeScale.msToPx(sliceStart);
     const rectWidth = attrs.timeScale.msToPx(sliceEnd) - rectStart;
-    const shownStart = rectStart > attrs.width ? attrs.width : rectStart;
-    const shownWidth = rectWidth + (rectStart as number) > attrs.width ?
-        attrs.width :
-        rectWidth;
-
-    if (attrs.trackContext.isOnCanvas()) {
-      attrs.trackContext.fillStyle = '#ccc';
-      attrs.trackContext.fillRect(0, 0, attrs.width, 73);
-
-      GridlineHelper.drawGridLines(
-          attrs.trackContext, attrs.timeScale, [0, 1000000], attrs.width, 73);
-
-      attrs.trackContext.fillStyle = '#c00';
-      attrs.trackContext.fillRect(shownStart, 40, shownWidth, 30);
-
-      attrs.trackContext.font = '16px Arial';
-      attrs.trackContext.fillStyle = '#000';
-      attrs.trackContext.fillText(
-          attrs.name + ' rendered by canvas', shownStart, 60);
-    }
 
     return m(
         '.track',
@@ -54,11 +46,13 @@
             position: 'absolute',
             top: attrs.top.toString() + 'px',
             left: 0,
-            width: '100%'
+            width: '100%',
+            height: `${attrs.trackState.height}px`,
           }
         },
         m(TrackShell,
-          attrs,
+          {name: attrs.trackState.name},
+          // TODO(dproy): Move out DOM Content from the track class.
           m('.marker',
             {
               style: {
@@ -69,12 +63,21 @@
                 background: '#aca'
               }
             },
-            attrs.name + ' DOM Content')));
+            attrs.trackState.name + ' DOM Content')));
+  },
+
+  onupdate({attrs}) {
+    // TODO(dproy): Figure out how track implementations should render DOM.
+    if (attrs.trackContext.isOnCanvas()) {
+      this.trackImpl.draw(attrs.trackContext, attrs.width, attrs.timeScale);
+    }
   }
 } as m.Component<{
-  name: string,
   trackContext: VirtualCanvasContext,
   top: number,
   width: number,
-  timeScale: TimeScale
-}>;
\ No newline at end of file
+  timeScale: TimeScale,
+  trackState: TrackState,
+},
+                     // TODO(dproy): Fix formatter. This is ridiculous.
+                     {trackImpl: TrackImpl}>;