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"]'));