<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
	"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
<refentry id="cockpit-series-data">
  <refnamediv>
    <refname>cockpit.js: Series Data</refname>
    <refpurpose>Representing series data</refpurpose>
  </refnamediv>

  <refsynopsisdiv>

  <para>Series data consists of values along a continuous (usually time) axis. We
    can place these in grids which expose a distinct subset of these values. These are
    the underlying mechanism for displaying metrics data in graphs.</para>
  </refsynopsisdiv>

  <refsection id="cockpit-grid">
    <title>cockpit.grid()</title>
<programlisting>
grid = cockpit.grid(interval, [beg, end])
</programlisting>

    <para>Creates a grid object to contain series data.</para>

    <para>The <code>interval</code> is the granularity of the grid. Usually this is
      a number of milliseconds, when used with time series data. The <code>beg</code>
      and <code>end</code> are the bounds of the grid. If omitted they will be set to
      zero for an initially empty grid.</para>

    <para>If <code>beg</code> and/or <code>end</code> are negative (including negative
      zero) then they are interpreted in number of intervals relative to the current
      time. Thus cockpit.grid(1000, -300, -0) will create a grid for the most recent
      5 minutes.</para>
  </refsection>

  <refsection id="cockpit-grid-add">
    <title>grid.add()</title>
<programlisting>
row = grid.add(series, path)
row = grid.add(callback, [early])
row = grid.add()
</programlisting>

    <para>Adds a row to the grid. The returned <code>row</code> is a Javascript array that will contain
      series data. The arguments control how the row is populated from the series data.
      The <code>row</code> is a sparse array. Its <code>row.length</code> will not match the
      expected size of the grid, unless and until the row has been completely filled in. The first
      index of the <code>row</code> will contain the data from the series data at the
      <link linkend="cockpit-grid-beg"><code>grid.beg</code></link> offset.</para>

    <para>When no arguments are passed, an empty row is added, and it is not populated with data.</para>

    <para>When called with a <code>series</code> and <code>path</code> argument then the row
      will be populated directly with series data. The <code>series</code> can either be a
      <link linkend="cockpit-series">series object</link> or an object that has an <code>obj.series</code>
      property. The <link linkend="cockpit-series-interval">series interval</link> must match the
      interval of this grid.
      If <code>path</code> is missing or empty, then the series data is placed into the row
      directly. Otherwise <code>path</code> indicates which part of the series data to place in the
      row. When <code>path</code> is an array, it is used as a set of property names or array indexes
      to follow into nested series data. When <code>path</code> is a dotted string, it is split and used
      the same way to locate the correct value in nested series data. The exact format of the series
      data depends on its producer, and relevant paths will be documented there.</para>

    <para>If a <code>callback</code> function is specified, then it will be invoked to provide series data
      for the row. The function is invoked as <code>callback(row, index, count)</code>, where the
      <code>row</code> is the row to fill in, the <code>index</code> is the index to start filling in and
      <code>count</code> is the number of items to fill in. The <code>this</code> variable will be set
      to the grid while invoking the <code>callback</code>. The callback is called after other data
      rows for a given series have been filled in. Callbacks are called in the order added, unless the
      <code>early</code> argument is set to <code>true</code>, in which case the callback is called earlier
      than callbacks without the <code>early</code> argument set.</para>

    <para>To remove the row use the
      <link linkend="cockpit-grid-remove"><code>grid.remove()</code> method.</link>
    </para>

    <para>The row will start being populated with data when the <code>series</code> produces data.
      To make this happen right away, use the
      <link linkend="cockpit-grid-sync"><code>grid.sync()</code></link> method.</para>

  </refsection>

  <refsection id="cockpit-grid-remove">
    <title>grid.remove()</title>
<programlisting>
grid.remove(row)
</programlisting>

    <para>Remove a previously added <code>row</code> from the grid. The row will no longer be updated
      with series data.</para>
  </refsection>

  <refsection id="cockpit-grid-sync">
    <title>grid.sync()</title>
<programlisting>
grid.sync()
</programlisting>

    <para>Load or reload data from the series into the rows. This does not clear the rows before
      populating them. Some data may be populated immediately, others may have to wait until data
      can be loaded. Internally this function calls
      <link linkend="cockpit-series-load"><code>series.load()</code></link> for each series.</para>

    <para>All rows with callbacks will be invoked to regenerate all the data. The
      <link linkend="cockpit-grid-onnotify"><code>grid.onnotify</code></link> event will be triggered.
      It is not necessary to call this function after a call of the
      <link linkend="cockpit-grid-move"><code>grid.move()</code></link> method.</para>

  </refsection>

  <refsection id="cockpit-grid-move">
    <title>grid.move()</title>
<programlisting>
grid.move(beg[, end])
</programlisting>

    <para>Move the grid to new <code>beg</code> and <code>end</code> range. Data will be
      discarded from the rows and <link linkend="cockpit-grid-sync"><code>grid.sync()</code></link>
      will be called to load or reload series data for the new range of offsets.</para>

    <para>If <code>end</code> is not specified it will be set to <code>beg</code>. If <code>beg</code>
      and/or <code>end</code> are negative (including negative zero) then they will be set to the
      number of intervals prior to the current time taken as an interval.</para>

    <para>If <code>beg</code> and/or <code>end</code> are negative (including negative
      zero) then they are interpreted in number of intervals relative to the current
      time. Thus cockpit.grid(1000, -300, -0) will create a grid for the most recent
      5 minutes.</para>
  </refsection>

  <refsection id="cockpit-grid-walk">
    <title>grid.walk()</title>
<programlisting>
grid.walk()
</programlisting>

    <para>Move the grid forward every
      <link linkend="cockpit-grid-interval"><code>grid.interval</code></link> milliseconds. To stop
      moving forward, call <link linkend="cockpit-grid-move"><code>grid.move()</code></link>.</para>
  </refsection>

  <refsection id="cockpit-grid-notify">
    <title>grid.notify()</title>
<programlisting>
grid.notify(index, count)
</programlisting>

    <para>This function is called to have rows with callbacks recalculate their data. It is not
      normally necessary to call this function, as it will be invoked automatically when new
      series data is available or has been loaded. This function triggers the
      <link linkend="cockpit-grid-onnotify"><code>grid.onnotify</code></link> event.</para>

  </refsection>

  <refsection id="cockpit-grid-onnotify">
    <title>grid.onnotify</title>
<programlisting>
grid.addEventListener("notify", function(index, count) { ... });
</programlisting>

    <para>An event that is triggered when some part of the series data in grid changes. The
      <code>index</code> is the row index where things changed, and the <code>count</code>
      is the length of the data that changed.</para>

  </refsection>

  <refsection id="cockpit-grid-close">
    <title>grid.close()</title>
<programlisting>
grid.close()
</programlisting>

    <para>Close the grid, and stop updating the rows.</para>
  </refsection>

  <refsection id="cockpit-grid-interval">
    <title>grid.interval</title>

    <para>The granularity of the grid. For time series data this is an interval in
      milliseconds. In order to use a given
      <link linkend="cockpit-grid">grid</link> and
      <link linkend="cockpit-series">series</link> together, their interval properties
      must match.</para>
  </refsection>

  <refsection id="cockpit-grid-beg">
    <title>grid.beg</title>

    <para>The beginning offset of the series data in the grid. Do not set this property
      directly. Use the <link linkend="cockpit-grid-move">grid.move()</link> method instead.</para>
  </refsection>

  <refsection id="cockpit-grid-end">
    <title>grid.end</title>

    <para>The ending offset of the series data in the grid. Do not set this property
      directly. Use the <link linkend="cockpit-grid-move">grid.move()</link> method instead.</para>
  </refsection>

  <refsection id="cockpit-series">
    <title>cockpit.series()</title>
<programlisting>
series = cockpit.series(interval, [cache, fetch])
</programlisting>

    <para>Create a new sink of series data. This is usually done by producers of series data,
      and it is rare to invoke this function directly.</para>

    <para>The <code>interval</code> is the granularity of the series data. For time series data
      this is an interval in milliseconds. If a <code>cache</code> string is specified, series data
      will be cached across frames for series with the same <code>cache</code> cache identifier
      to load and/or reload.</para>

    <para>If a <code>fetch</code> callback
      is specified, then it will be invoked when grids request certain ranges of data. The
      <code>fetch</code> callback is invoked with <code>function fetch(beg, end) { ... }</code>
      range offsets. The <link linkend="cockpit-series-input">series.input()</link> should be
      called with data retrieved, either immediately or at a later time. The callback may be
      called multiple times for the same ranges of data. It is up to the callback to determine
      when or whether it should retrieve the data more than once.</para>

    <para>A producer of series data, usually calls this function and creates itself a
      <code>obj.series</code> property containing this series object.</para>
  </refsection>

  <refsection id="cockpit-series-input">
    <title>series.input()</title>
<programlisting>
series.input(beg, items[, mapping])
</programlisting>

    <para>Send series data into the series sink. Any grids that have added rows based on this
      series, will have data filled in. The <code>beg</code> is the beginning offset of
      <code>items</code>. The <code>items</code> are an array one or more series data items.</para>

    <para>Producers may wish to provide additional properties that can be used in lookup paths that
      rows can pull from. This is done in the <code>mapping</code> argument. If specified it is
      a tree of objects. Each sub object should have a property with the name <code>""</code>
      empty string, which will be used as the property name or index in place of the one used
      in the lookup path.</para>

  </refsection>

  <refsection id="cockpit-series-load">
    <title>series.load()</title>
<programlisting>
series.load(beg, end)
</programlisting>

    <para>Load data from the series into any grids that have rows based on this series data.
      Any cached data will be filled in immediately. Any data not cached, will be requested
      from the producer, if possible, and may arrive at a later time.</para>

    <para>The <code>beg</code> and <code>end</code> denote the range of data to load.</para>
  </refsection>

  <refsection id="cockpit-series-interval">
    <title>series.interval</title>

    <para>The granularity of the series. For time series data this is an interval in
      milliseconds. In order to use a given
      <link linkend="cockpit-grid">grid</link> and
      <link linkend="cockpit-series">series</link> together, their interval properties
      must match.</para>
  </refsection>

  <refsection id="cockpit-series-limit">
    <title>series.limit</title>

    <para>The maximum number of items to cache for loading and/or reloading. You can
      change this value to a different number. Having a number close to zero will break
      certain usage of grids, such as
      <link linkend="cockpit-grid-walk"><code>grid.walk()</code></link>.</para>
  </refsection>

</refentry>
