Last updated

Combo Layers

This Time Series – Combo Layers tutorial allows adding a different shape to each of two predefined layers in one Time Series widget. Two layers are provided for client applications, into which any custom shape or visual can be added. The first "front" layer is in front of the curve visuals and behind the tooltip and cursor. The second "back" layer is behind the curve visuals.

To create a Time Series widget, please refer to Time Series Basics tutorial. See the Charts - Combo Chart tutorial for non-Time Series combined displays.

# Bar Combo Layers

The Time Series widget can combine a bar chart layer with a line chart layer using the same time range.

import { Group } from "@int/geotoolkit/scene/Group.ts";
import { Rect } from "@int/geotoolkit/util/Rect.ts";
import { TimeSeriesWidget } from "@int/geotoolkit/widgets/TimeSeriesWidget.ts";
import { ScrollBarType } from "@int/geotoolkit/widgets/timeseries/ScrollBarType.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
import { BarChart, BarMode, BarValueLocation, DataMode, Orientation } from "@int/geotoolkit/controls/shapes/BarChart.ts";
import { AlignmentStyle, BaseLineStyle } from "@int/geotoolkit/attributes/TextStyle.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { getDataTables } from "/src/code/TimeSeries/data.ts";
import { computeBarChartData, getUTCTime } from "/src/code/TimeSeries/datasource.ts";
function createScene(canvas) {
  const startDate = new Date(2013, 0, 1).getTime();
  const endDate = new Date(2014, 0, 1).getTime();
  const dataTableViews = getDataTables(startDate, endDate);
  const curveIndice = [0];
  const names = ["GR"];
  const colors = [
    "rgba(21, 101, 192, 0.85)"
  ];
  function createWidget() {
    const options = {
      "model": new Group().setModelLimits(new Rect(startDate, 0, endDate, 1)),
      "scrollbar": {
        "type": ScrollBarType.Simple,
        "height": 10,
        "options": {
          "rounded": true,
          "resizable": true
        }
      }
    };
    return new TimeSeriesWidget(options);
  }
  function addCurves(widget2) {
    curveIndice.forEach((curveIndex, index) => {
      widget2.addCurve({
        "name": names[index],
        "uri": "//test//" + names[index].toLowerCase(),
        "data": dataTableViews[curveIndex],
        "properties": {
          "autoscale": true,
          "axisautolabelrotation": true,
          "neatlimits": true,
          "unit": "API",
          "linestyle": {
            "color": colors[index],
            "width": 2
          }
        }
      });
    });
  }
  function addBars(widget2) {
    const barData = computeBarChartData("curve1", 3e4);
    const barChartData = {
      "mode": DataMode.Associative,
      "datasets": [
        { "values": barData.maxValues }
      ]
    };
    const options = {
      "barstyles": [
        {
          "linestyles": KnownColors.Green,
          "fillstyles": KnownColors.Green
        }
      ],
      "barmode": BarMode.Default,
      "valuelimits": {
        "minvalue": barData.min,
        "maxvalue": barData.max
      },
      "barvalues": {
        "location": BarValueLocation.TopOutside,
        "visible": true,
        "rotationangle": 1.5708,
        "textstyle": {
          "color": "white",
          "font": "10px Arial",
          "baseline": BaseLineStyle.Hanging,
          "alignment": AlignmentStyle.Center
        },
        "margins": {
          "anchorx": 5,
          "anchory": -2
        }
      },
      "barwidth": 5,
      "barpad": 1,
      "orientation": Orientation.Bottom
    };
    const barChart = new BarChart();
    barChart.setOptions(options);
    barChart.setData(barChartData);
    barChart.setVerticalFlip(true);
    widget2.getVisualBackLayer().addChild(barChart);
  }
  const widget = createWidget();
  addCurves(widget);
  addBars(widget);
  widget.scaleModel(2);
  widget.setVisibleRange(new Range(getUTCTime(2013, 1, 1), getUTCTime(2013, 7, 1)));
  return new Plot({
    "canvaselement": canvas,
    "root": widget
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

# Tornado Combo Layers

This Times Series widget combines a Tornado Chart layer with a Line Chart layer using the same time range. A Tornado Chart displays data categories vertically instead of horizontally and the categories are ordered so that the largest bars appear at the center top of the chart.

import { Group } from "@int/geotoolkit/scene/Group.ts";
import { Rect } from "@int/geotoolkit/util/Rect.ts";
import { TimeSeriesWidget } from "@int/geotoolkit/widgets/TimeSeriesWidget.ts";
import { ScrollBarType } from "@int/geotoolkit/widgets/timeseries/ScrollBarType.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
import { BarChart, BarMode, BarValueLocation, DataMode, Orientation } from "@int/geotoolkit/controls/shapes/BarChart.ts";
import { AlignmentStyle, BaseLineStyle } from "@int/geotoolkit/attributes/TextStyle.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { getDataTables } from "/src/code/TimeSeries/data.ts";
import { computeBarChartData, getTimeBaseData, getUTCTime } from "/src/code/TimeSeries/datasource.ts";
function createScene(canvas) {
  const startDate = new Date(2013, 0, 1).getTime();
  const endDate = new Date(2014, 0, 1).getTime();
  const dataTableViews = getDataTables(startDate, endDate);
  const timeBasedData = getTimeBaseData();
  const curveIndice = [3];
  const names = ["CALI"];
  const colors = [
    "rgba(124, 179, 66, 0.85)"
  ];
  function createWidget() {
    const options = {
      "model": new Group().setModelLimits(new Rect(startDate, 0, endDate, 1)),
      "scrollbar": {
        "type": ScrollBarType.Simple,
        "height": 10,
        "options": {
          "resizable": true,
          "rounded": true
        }
      }
    };
    return new TimeSeriesWidget(options);
  }
  function addCurves(widget2) {
    curveIndice.forEach((curveIndex, index) => {
      widget2.addCurve({
        "name": names[index],
        "uri": "//test//" + names[index].toLowerCase(),
        "data": dataTableViews[curveIndex],
        "properties": {
          "autoscale": true,
          "axisautolabelrotation": true,
          "neatlimits": true,
          "unit": "API",
          "linestyle": {
            "color": colors[index],
            "width": 2
          }
        }
      });
    });
  }
  function createMaxValueBars(barData) {
    const barChartData = {
      "mode": DataMode.Associative,
      "datasets": [
        { "values": barData.maxValues }
      ]
    };
    const options = {
      "barstyles": [
        {
          "linestyles": KnownColors.Blue,
          "fillstyles": KnownColors.Blue
        }
      ],
      "barmode": BarMode.Stacked,
      "valuelimits": {
        "minvalue": barData.min,
        "maxvalue": barData.max
      },
      "barvalues": {
        "location": BarValueLocation.TopOutside,
        "visible": true,
        "rotationangle": 1.5708,
        "textstyle": {
          "color": "white",
          "font": "10px Arial",
          "baseline": BaseLineStyle.Alphabetic,
          "alignment": AlignmentStyle.Center
        },
        "margins": {
          "anchorx": 5,
          "anchory": 0
        }
      },
      "barwidth": 5,
      "barpad": 1,
      "orientation": Orientation.Bottom
    };
    const barChart = new BarChart();
    barChart.setOptions(options);
    barChart.setData(barChartData);
    barChart.setVerticalFlip(true);
    return barChart;
  }
  function createMinValueBars(barData) {
    const barChartData = {
      "mode": DataMode.Associative,
      "datasets": [
        { "values": barData.minValues }
      ]
    };
    const options = {
      "barstyles": [
        {
          "linestyles": KnownColors.Orange,
          "fillstyles": KnownColors.Orange
        }
      ],
      "barmode": BarMode.Stacked,
      "valuelimits": {
        "minvalue": barData.min,
        "maxvalue": barData.max
      },
      "barvalues": {
        "location": BarValueLocation.TopOutside,
        "visible": true,
        "rotationangle": 1.5708,
        "textstyle": {
          "color": "white",
          "font": "10px Arial",
          "baseline": BaseLineStyle.Alphabetic,
          "alignment": AlignmentStyle.Center
        },
        "margins": {
          "anchorx": -5,
          "anchory": 0
        }
      },
      "barwidth": 5,
      "barpad": 1,
      "orientation": Orientation.Bottom
    };
    const barChart = new BarChart();
    barChart.setOptions(options);
    barChart.setData(barChartData);
    barChart.setVerticalFlip(false);
    return barChart;
  }
  function addBars(widget2) {
    const barData = computeBarChartData("curve1", 3e4);
    const timeCurve = timeBasedData["index"];
    const timeValues = timeCurve["values"];
    const maxBarChart = createMaxValueBars(barData);
    const minBarChart = createMinValueBars(barData);
    const barGroup = new Group();
    barGroup.setModelLimits(new Rect(timeValues[0] * 1e3, 0, timeValues[timeValues.length - 1] * 1e3, barData.max));
    const maxBarChartGroup = new Group();
    maxBarChartGroup.addChild(maxBarChart);
    const minBarChartGroup = new Group();
    minBarChartGroup.addChild(minBarChart);
    maxBarChartGroup.setModelLimits(new Rect(timeValues[0] * 1e3, 0, timeValues[timeValues.length - 1] * 1e3, barData.max / 2));
    maxBarChartGroup.setBounds(new Rect(timeValues[0] * 1e3, 0, timeValues[timeValues.length - 1] * 1e3, barData.max / 2));
    minBarChartGroup.setModelLimits(
      new Rect(timeValues[0] * 1e3, barData.max / 2, timeValues[timeValues.length - 1] * 1e3, barData.max)
    );
    minBarChartGroup.setBounds(
      new Rect(timeValues[0] * 1e3, barData.max / 2, timeValues[timeValues.length - 1] * 1e3, barData.max)
    );
    barGroup.addChild([maxBarChartGroup, minBarChartGroup]);
    widget2.getVisualBackLayer().addChild(barGroup);
  }
  const widget = createWidget();
  addCurves(widget);
  addBars(widget);
  widget.scaleModel(2);
  widget.setVisibleRange(new Range(getUTCTime(2013, 1, 1), getUTCTime(2013, 7, 1)));
  return new Plot({
    "canvaselement": canvas,
    "root": widget
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

# Box Plot Combo Layers

This Times Series widget combines a Box Plot Chart layer with a Line Chart layer using the same time range. A box plot is a graphical rendition of data, arranged horizontally or vertically, based on a five number summary: minimum, first quartile, median, third quartile, and maximum. The vertical lines extending from the boxes are called “whiskers”. For more information about Box Plot charts, see Charts - Box Plot.

import { Group } from "@int/geotoolkit/scene/Group.ts";
import { Rect } from "@int/geotoolkit/util/Rect.ts";
import { TimeSeriesWidget } from "@int/geotoolkit/widgets/TimeSeriesWidget.ts";
import { ScrollBarType } from "@int/geotoolkit/widgets/timeseries/ScrollBarType.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
import { BoxPlot, BoxValueLocation, DataMode } from "@int/geotoolkit/controls/shapes/BoxPlot.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { Orientation } from "@int/geotoolkit/util/Orientation.ts";
import { getDataTables } from "/src/code/TimeSeries/data.ts";
import { computeBarChartData, getUTCTime } from "/src/code/TimeSeries/datasource.ts";
function createScene(canvas) {
  const startDate = new Date(2013, 0, 1).getTime();
  const endDate = new Date(2014, 0, 1).getTime();
  const dataTableViews = getDataTables(startDate, endDate);
  const curveIndice = [0];
  const names = ["GR"];
  const colors = [
    "rgba(128, 128, 128, 0.85)"
  ];
  function createWidget() {
    const options = {
      "model": new Group().setModelLimits(new Rect(startDate, 0, endDate, 1)),
      "scrollbar": {
        "type": ScrollBarType.Simple,
        "height": 10,
        "options": {
          "resizable": true,
          "rounded": true
        }
      }
    };
    return new TimeSeriesWidget(options);
  }
  function addCurves(widget2) {
    curveIndice.forEach((curveIndex, index) => {
      widget2.addCurve({
        "name": names[index],
        "uri": "//test//" + names[index].toLowerCase(),
        "data": dataTableViews[curveIndex],
        "properties": {
          "autoscale": true,
          "axisautolabelrotation": true,
          "neatlimits": true,
          "unit": "API",
          "linestyle": {
            "color": colors[index],
            "width": 2
          }
        }
      });
    });
  }
  function addBars(widget2) {
    const barData = computeBarChartData("curve1", 3e4);
    const oilCurveRawValues = barData["valuesBinArray"];
    const colorstyle = {
      "primaryfillstyle": KnownColors.Green,
      "secondaryfillstyle": KnownColors.Red
    };
    const options = {
      "fixedboxwidth": 0.5,
      "boxpad": 2,
      "winskerswidth": 2,
      "boxwidthunit": "cm",
      "linestyle": "blue",
      "valuelimits": {
        "minvalue": barData.min,
        "maxvalue": barData.max
      },
      "boxvalues": {
        "visible": false,
        "suppress": true,
        "textstyle": {
          "font": "8px sans-serif",
          "color": "white"
        },
        "location": BoxValueLocation.Right,
        "horizontaloffset": 2,
        "decimalprecision": 2
      },
      "orientation": Orientation.Vertical,
      "connectedlinestyle": {
        "color": "blue"
      }
    };
    const boxPlotData = {
      "mode": DataMode.Raw,
      "datasets": [
        {
          "values": oilCurveRawValues,
          "fillstyle": colorstyle
        }
      ]
    };
    const boxPlotShape = new BoxPlot(options, boxPlotData);
    const boxPlotGroup = new Group();
    boxPlotGroup.addChild(boxPlotShape);
    boxPlotGroup.setModelLimits(boxPlotShape.getModelLimits());
    boxPlotGroup.setVerticalFlip(true);
    widget2.getVisualBackLayer().addChild(boxPlotGroup);
  }
  const widget = createWidget();
  addCurves(widget);
  addBars(widget);
  widget.scaleModel(2);
  widget.setVisibleRange(new Range(getUTCTime(2013, 1, 1), getUTCTime(2013, 7, 1)));
  return new Plot({
    "canvaselement": canvas,
    "root": widget
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));