Last updated

Animations

This tutorial describes how to add basic animation to a Time Series Widget. To create the basic Time Series Widget, please refer to Time Series Basics tutorial.

# Animation

The following example demonstrates a basic Time Series widget with the added animation and easing function 'EaseOutBack'.

import { DateUtil } from "@int/geotoolkit/util/DateUtil.ts";
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 { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { LineStyle, Patterns } from "@int/geotoolkit/attributes/LineStyle.ts";
import { AnimationStyle } from "@int/geotoolkit/attributes/AnimationStyle.ts";
import { Direction } from "@int/geotoolkit/layout/HorizontalPriorityLayout.ts";
import { AdaptiveDateTimeTickGenerator } from "@int/geotoolkit/axis/AdaptiveDateTimeTickGenerator.ts";
import { DateTimeFormat } from "@int/geotoolkit/util/DateTimeFormat.ts";
import { DataTable } from "@int/geotoolkit/data/DataTable.ts";
import { DataTableView } from "@int/geotoolkit/data/DataTableView.ts";
import { Functions } from "@int/geotoolkit/animation/Easing.ts";
import { getDataTables } from "/src/code/TimeSeries/data.ts";
const timeouts = [];
let interval;
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, 1];
  const names = ["CALI", "GR"];
  const units = ["INS", "API"];
  const limits = [{
    "min": 0,
    "max": 15
  }, {
    "min": 0,
    "max": 150
  }];
  const colors = [
    "rgba(21, 101, 192, 0.85)",
    "rgba(239, 108, 0, 0.85)"
  ];
  const style = new AnimationStyle([{
    "attributename": "data",
    "begin": "auto",
    "duration": 1500,
    "function": Functions.EaseOutBack
  }]);
  function addCurves(widget2) {
    curveIndice.forEach((curveIndex, index) => {
      widget2.addCurve({
        "name": names[index],
        "uri": "//test//" + names[index].toLowerCase(),
        "data": dataTableViews[curveIndex],
        "properties": {
          ...limits[index],
          "autoscale": false,
          "neatlimits": true,
          "unit": units[index],
          "linestyle": {
            "color": colors[index],
            "width": 2
          },
          "axisposition": index % 2 === 0 ? "right" : "left"
        }
      });
    });
  }
  function customizeCSS(widget2) {
    widget2.setAnimationStyle(style);
    const css = `
            *[cssclass~="layoutgroup"]{
                fillstyle: #284258;
            }
            .TimeSeriesWidget {
                tooltips-tooltipoptions-textcolor: #e1dcdc;
            }
            .geotoolkit.axis.Axis {
                tickgenerator-edge-labelstyle-color: rgba(255,255,255, 1);
            }
        `;
    widget2.setCss(css);
  }
  function createWidget() {
    const options = {
      "curvelimits": {
        "visible": false
      },
      "curveaxis": {
        "visible": true,
        "autocoloraxis": true,
        "autocolorlabel": false,
        "axiswidth": 60,
        "textcolor": "#ffffff",
        "tickgeneratoroptions": {
          "major": {
            "labelvisible": true
          }
        },
        "titlevisible": false,
        "compact": false
      },
      "cursor": {
        "linestyle": {
          "color": "rgba(255,255,255,1)",
          "width": 0.5,
          "pattern": Patterns.Solid
        }
      },
      "intervalbuttons": {
        "visible": false
      },
      "lastupdatedate": {
        "visible": false
      },
      "legends": {
        "direction": Direction.RightToLeft,
        "legendoptions": {
          "fillstyle": "#284258",
          "linestyle": "#284258"
        }
      },
      "model": new Group().setModelLimits(new Rect(startDate, 0, endDate, 1)),
      "scrollbar": {
        "visible": false
      },
      "southaxis": {
        "color": "#ffffff",
        "font": "12px Arial",
        "height": 30,
        "tickgenerator": new AdaptiveDateTimeTickGenerator().setFormatLabelHandler((tickgen, parent, orient, info, index, value) => DateUtil.formatUTC(new Date(value), "M d"))
      },
      "title": {
        "text": "",
        "height": 20,
        "color": "#ffffff",
        "visible": true,
        "padding": [0, 0, 0, 5]
      },
      "tooltips": {
        "selectionradius": Number.POSITIVE_INFINITY,
        "tooltipoptions": {
          "index": {
            "name": "",
            "visible": true,
            "formatter": new DateTimeFormat({ "format": "M d" }),
            "textcolor": "#e1dcdc"
          },
          "textcolor": "#e1dcdc"
        },
        "fillstyle": "rgba(100,100,100,0.8)",
        "linestyle": LineStyle.Empty
      },
      "visiblerange": {
        "visible": false
      }
    };
    return new TimeSeriesWidget(options);
  }
  function setDataWidget(curves, dataTableView, widget2) {
    curves.forEach((curve, index) => {
      const timeSeriesObject = widget2.getTimeSeriesObjectById(curve);
      if (timeSeriesObject != null) {
        timeSeriesObject.setData(dataTableView[index]);
      }
    });
  }
  function addAnimations(widget2) {
    const arrayZeros = new Array(1e3).fill(0);
    const dataTable = [];
    const dataTableView = [];
    for (let i = 0; i < 2; i++) {
      dataTable[i] = new DataTable({ "cols": [
        { "type": "number", "data": dataTableViews[i].getDataTable().getColumn(0).toArray() },
        { "type": "number", "data": arrayZeros }
      ] });
      dataTableView[i] = new DataTableView(dataTable[i]);
    }
    const curves = widget2.getCurves();
    widget2.getTool().getToolByName("manipulatorTools.cursor").setEnabled(false);
    timeouts.push(window.setTimeout(() => {
      setDataWidget(curves, dataTableViews, widget2);
      widget2.updateState();
    }, 300));
    timeouts.push(window.setTimeout(() => {
      widget2.getTool().getToolByName("manipulatorTools.cursor").setEnabled(true);
    }, 1800));
    interval = window.setInterval(() => {
      widget2.getTool().getToolByName("manipulatorTools.cursor").setEnabled(false);
      widget2.setAnimationStyle(null);
      setDataWidget(curves, dataTableView, widget2);
      widget2.setAnimationStyle(style);
      timeouts.push(window.setTimeout(() => {
        setDataWidget(curves, dataTableViews, widget2);
        widget2.updateState();
      }, 1e3));
      timeouts.push(window.setTimeout(() => {
        widget2.getTool().getToolByName("manipulatorTools.cursor").setEnabled(true);
      }, 2500));
    }, 5e3);
  }
  const widget = createWidget();
  addCurves(widget);
  customizeCSS(widget);
  addAnimations(widget);
  return new Plot({
    "canvaselement": canvas,
    "root": widget
  });
}
function dispose() {
  timeouts.forEach((timeout) => {
    clearTimeout(timeout);
  });
  clearInterval(interval);
}
export { createScene, dispose };

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

# Symbol Animation

The following example demonstrates the symbol animation for the Time Series Widget.

import { DateUtil } from "@int/geotoolkit/util/DateUtil.ts";
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 { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { Patterns } from "@int/geotoolkit/attributes/LineStyle.ts";
import { AnimationStyle } from "@int/geotoolkit/attributes/AnimationStyle.ts";
import { Direction } from "@int/geotoolkit/layout/HorizontalPriorityLayout.ts";
import { AdaptiveDateTimeTickGenerator } from "@int/geotoolkit/axis/AdaptiveDateTimeTickGenerator.ts";
import { CirclePainter } from "@int/geotoolkit/scene/shapes/painters/CirclePainter.ts";
import { from } from "@int/geotoolkit/selection/from.ts";
import { SymbolShape } from "@int/geotoolkit/scene/shapes/SymbolShape.ts";
import { ToolTipTool } from "@int/geotoolkit/controls/tools/ToolTipTool.ts";
import { Point } from "@int/geotoolkit/util/Point.ts";
import { getDataTables } from "/src/code/TimeSeries/data.ts";
import { MarkerFactory } from "/src/code/TimeSeries/Animations/markerFactory.ts";
function createToolTipTool(widget, tooltip) {
  const markers = [];
  const manipulatorLayer = from(widget).where('node => id(node) == "manipulator_layer"').selectFirst();
  const style = "margin-right: 5px; height: 10px; width: 10px; background-color: transparent; border-radius: 50%; display: inline-block;";
  return new ToolTipTool({
    "divelement": tooltip,
    "layer": widget,
    "init": () => {
      const duration = 500;
      const style2 = new AnimationStyle([{
        "attributename": "width",
        "duration": duration,
        "begin": "auto"
      }, {
        "attributename": "height",
        "duration": duration,
        "begin": "auto"
      }, {
        "attributename": "visible",
        "duration": duration,
        "begin": "auto"
      }]);
      widget.getCurves().forEach(
        () => markers.push(
          new MarkerFactory(() => new SymbolShape({
            "ax": 0,
            "ay": 0,
            "width": 15,
            "height": 15,
            "sizeisindevicespace": true,
            "linestyle": {
              "color": "white",
              "width": 3,
              "shadow": {
                "enable": true,
                "blur": 5,
                "color": "gray"
              }
            },
            "fillstyle": {
              "color": "transparent"
            },
            "painter": CirclePainter,
            "animationstyle": style2
          }), style2)
        )
      );
      manipulatorLayer.insertChild(0, new Group().addChild(markers).setVerticalFlip(true));
    },
    "callback": (pt) => {
      const lineData = widget.hitTest(pt);
      const results = [];
      lineData.forEach((data, index) => {
        const marker = markers[index];
        marker.setVisible(true);
        const curve = data["curve"];
        let symbolPoint = new Point(data["position"], data["value"]);
        if (curve.getWorldTransform() != null) {
          symbolPoint = curve.getWorldTransform().transformPoint(symbolPoint, symbolPoint);
        }
        marker.showMarker(symbolPoint, data["symbol"].getFillStyle().getColor(), CirclePainter);
        const timeSeriesObject = widget.getTimeSeriesObjectById(data["id"]);
        const formatter = timeSeriesObject.getTooltipOptions()["formatter"];
        const color = data["symbol"].getFillStyle().getColor();
        results.push(`<span style="${style} background-color: ${color}"></span><b>` + data["name"] + "</b> <br>Date: " + DateUtil.formatUTC(new Date(data["position"]), "M j H:i") + "<br>" + data["name"] + ": " + formatter.format(data["originalvalue"]) + (data["originalunit"] != null ? " (" + data["originalunit"] + ")" : "") + "<br>");
      });
      return results.join("<br>");
    }
  });
}
function createScene(canvas, tooltip) {
  const startDate = new Date(2013, 0, 1).getTime();
  const endDate = new Date(2014, 0, 1).getTime();
  const dataTableViews = getDataTables(startDate, endDate);
  const curveIndice = [0, 1];
  const names = ["CALI", "GR"];
  const units = ["INS", "API"];
  const limits = [{
    "min": 0,
    "max": 15
  }, {
    "min": 0,
    "max": 150
  }];
  const colors = [
    "rgba(21, 101, 192, 0.85)",
    "rgba(255, 0, 0, 0.85)"
  ];
  function addCurves(widget2) {
    curveIndice.forEach((curveIndex, index) => {
      widget2.addCurve({
        "name": names[index],
        "uri": "//test//" + names[index].toLowerCase(),
        "data": dataTableViews[curveIndex],
        "properties": {
          ...limits[index],
          "autoscale": false,
          "neatlimits": true,
          "unit": units[index],
          "linestyle": {
            "color": colors[index],
            "width": 2
          },
          "axisposition": index % 2 === 0 ? "right" : "left"
        }
      });
    });
  }
  function customizeCSS(widget2) {
    const css = `
            .geotoolkit.axis.Axis {
              tickgenerator-edge-labelstyle-color: rgba(0,0,0, 1);
            }
        `;
    widget2.setCss(css);
  }
  function createWidget() {
    const options = {
      "curvelimits": {
        "visible": false
      },
      "curvesymbol": {
        "visible": false
      },
      "curveaxis": {
        "visible": true,
        "autocoloraxis": true,
        "autocolorlabel": false,
        "axiswidth": 60,
        "textcolor": "#ffffff",
        "tickgeneratoroptions": {
          "major": {
            "labelvisible": true
          }
        },
        "titlevisible": false,
        "compact": false
      },
      "cursor": {
        "linestyle": {
          "color": "rgba(255,255,255,1)",
          "width": 0.5,
          "pattern": Patterns.Solid
        }
      },
      "intervalbuttons": {
        "visible": false
      },
      "lastupdatedate": {
        "visible": false
      },
      "legends": {
        "direction": Direction.RightToLeft
      },
      "model": new Group().setModelLimits(new Rect(startDate, 0, endDate, 1)),
      "scrollbar": {
        "visible": false
      },
      "southaxis": {
        "color": "#ffffff",
        "font": "10px Arial",
        "height": 30,
        "tickgenerator": new AdaptiveDateTimeTickGenerator().setFormatLabelHandler((tickgen, parent, orient, info, index, value) => DateUtil.formatUTC(new Date(value), "M d Y"))
      },
      "title": {
        "text": "",
        "height": 20,
        "color": "#ffffff",
        "visible": true,
        "padding": [0, 0, 0, 5]
      },
      "tooltips": {
        "visible": false
      },
      "visiblerange": {
        "visible": false
      }
    };
    return new TimeSeriesWidget(options);
  }
  const widget = createWidget();
  addCurves(widget);
  customizeCSS(widget);
  widget.connectTool(createToolTipTool(widget, tooltip));
  return new Plot({
    "canvaselement": canvas,
    "root": widget
  });
}
export { createScene };

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