src/PlotArea.ts

   1/**

   2 * ## PlotArea

   3 * Plots data as an area. `PlotArea` is called if the series' `type` is 'area'.

   4 * The area will be filled between a series as indexed by `y` and the x-axis, 

   5 * or a second series indexed by `yBase`.

   6 * If `yBase` equals `$stacked`, subsequent series will be stacked upon each other.

   7 * `PlotArea` recognizes the following attributes:

   8 * - `x`: name of the x series

   9 * - `y`: name of the y series, also used as higher series when filling against `yBase`

  10 * - `yBase`: optional lower series to fill against instead of the x-axis. 

  11 * - `map`: Use 'stacked' to stack series upon each other. Use 'shared' to show the share of

  12 *    each series, normalized to 1.

  13 * 

  14 * 

  15 * script.js'>

  16 * let series = {

  17 *    colNames:['time', 'volume', 'costs'],

  18 *    rows:[

  19 *      [-1,  0.2, 0.3],

  20 *      [0.2, 0.7, 0.2],

  21 *      [0.4, 0.1, 0.3],

  22 *      [0.6, 0,   0.1],

  23 *      [0.8, 0.3, 0.5],

  24 *      [1,   0.2, 0.4]

  25 * ]};

  26 * 

  27 * m.mount(root, { 

  28 *    view:() => m(hslayout.Layout, {

  29 *       rows: [],

  30 *       content: [

  31 *          m(hsgraph.Graph, {cfgFn: cfg => defCfg(cfg)}),

  32 *          m(hsgraph.Graph, {cfgFn: cfg => defCfg(cfg, 'stacked')}),

  33 *          m(hsgraph.Graph, {cfgFn: cfg => defCfg(cfg, 'shared')})

  34 *       ]

  35 *    })

  36 * });

  37 * function defCfg(cfg, map) {

  38 *     cfg.series.series = [

  39 *        { x:'time', y:'volume', map:map, type: 'area' },

  40 *        { x:'time', y:'costs',  map:map, type: 'area' }

  41 *     ];

  42 *     cfg.series.data      = [series];

  43 *     cfg.series.series[0].style.fill.color = 'rgba(128, 128, 255, 0.5)';

  44 *     cfg.series.series[1].style.fill.color = 'rgba(0, 128, 0, 0.5)';

  45 *     cfg.axes.primary.y.scale.domain = [0, 1];

  46 *     cfg.axes.primary.y.title.visible = false;

  47 *     cfg.chart.title.visible = false;

  48 * }

  49 * 

  50 * 

  51 * 

  52 */

  53

  54

  55/** */

  56export const m = require("mithril");

  57export type Vnode = typeof m.Vnode;

  58import { Data }         from 'hsdatab';

  59import { XYScale }      from './AxesTypes';

  60import { Plot }         from './Plot';

  61import { SeriesDef }    from './Series';

  62

  63export class PlotArea extends Plot { 

  64    plot(data:Data, series:SeriesDef, scales:XYScale, i:number, clipID:string): Vnode[] {

  65        const x     = data.colNumber(series.x);

  66        const y     = data.colNumber(series.y);

  67        const yBase = data.colNumber(series.yBase);  // or undefined

  68        const yMax  = data.colNumber('$sum');

  69        const mapRow = (row:any[]) =>

  70            (yMax===undefined)? [

  71                row[x],

  72                row[y]+row[yBase],

  73                row[yBase]

  74            ] : [

  75                row[x],

  76                (row[y]+row[yBase]) / row[yMax],

  77                row[yBase] / row[yMax]

  78            ]; 

  79        if (y===undefined) { return m('.error',''); }

  80        if (series.map) {

  81            const d = data.getData().map(mapRow);

  82            return [this.drawArea(clipID, d, 0, 1, 2, scales, series.style, series.y)];

  83        } else {

  84            const d = data.getData();

  85            return [this.drawArea(clipID, d, x, y, yBase, scales, series.style, series.y)];

  86        }

  87    }

  88}

  89