Skip to content

Data Sources

g$ edited this page Jan 9, 2018 · 13 revisions

This seems like extra work, I know! However, the benefits are worth the extra organization.

Consider the chart in the demo application (also shown on this wiki's Home page). It's building 4 different series from the same "row" of data. A naive strategy causes 4 separate traversals of the data set, one per series. With data sources, we get only one. Now you may correctly note: we have not really reduced the total number of operations. That's true (to an extent), but it's not where the benefits lie.

Friends With Benefits

Let's go down the list:

  • Dirty tracking: moving the Dirty tracking up to the data source now keeps all series "clean" after one pass.
  • Axis limits: instead of updating axes on each observation, this bookkeeping is deferred until after all observations were seen by all series, and performed once.
  • Modifications: any change to the (presumably) ObservableCollection is now observed by only one party, which organizes the refresh for all series.
  • Orchestration: it's now possible to coordinate/synchronize the changes to multiple series, via animation etc.
  • Parallelization: since we can't assume IEnumerable is thread-safe across multiple series, the consolidation now opens up the possibility to run all data sources in parallel!

Rendering Pipeline

The DataSource implementation organizes itself via renderers that register their IDataSourceRenderer interface with it. The Chart does this bookkeeping as Series enter and leave the Chart. These "listeners" are responsible for creating Geometry etc. corresponding to the values.

Renderers

A IDataSourceRenderer has these methods:

  • preamble: express interest in rendering pass.
    • A Renderer must (create and) return a state object it receives back in the other methods,
    • or return NULL to refrain from being called this pass.
  • render: process a value from the data source.
  • render-complete: all values were seen by all Renderers.
  • postamble: finalize calculations and commit drawing objects.

After this completes, the pipeline has ended, and the rest of the "higher-level" rendering process takes over; see Rendering for more information.

Algorithm

The Data Source rendering pipeline organizes into "phases":

  • I: Call preamble on all Renderers. Save the ones that return non-null for the following phases.
    • Each following phase (except IIIb) implicitly operates on this list.
  • II: For each data item, call render.
    • Construct Path and Geometry instances as required.
    • Cache information (if necessary) to use during postamble.
  • III: Call render-complete.
    • Create additional Geometry based on having seen all values.
  • IV: Call postamble.
    • Perform final "adjustments" on Path and/or Geometry.
    • Make Path and/or Geometry held in the state available to the rest of the component.
    • Dispose of any IDisposable used in the state.
Clone this wiki locally