Tutorial: Explore the Azure Time Series Insights JavaScript client library

The JavaScript D3-based Azure Time Series Insights client library was developed to help web developers query and visualize data stored in Time Series Insights. This tutorial guides you through the Time Series Insights client library and programming model by using a hosted sample app.

The tutorial details how to work with the library, how to access Time Series Insights data, and how to use chart controls to render and visualize data. You'll also learn how to experiment with different kinds of graphs to visualize data. At the end of the tutorial, you'll be able to use the client library to incorporate Time Series Insights features into your own web app.

Specifically, you'll learn about:

  • The Time Series Insights sample application
  • The Time Series Insights JavaScript client library
  • How the sample application uses the library to visualize Time Series Insights data

Note

Video

In this video, we introduce the open-source Time Series Insights JavaScript SDK:

Prerequisites

This tutorial uses your browser's Developer Tools feature. Modern web browsers (Microsoft Edge, Chrome, Firefox, Safari, and others) typically provide access to the Web Inspector View through the F12 hotkey on your keyboard. Another way to access the view is to right-click on a webpage, and then select Inspect Element.

Time Series Insights sample application

Throughout this tutorial, we use a free, hosted Time Series Insights sample app to explore the source code behind the application and to explore the Time Series Insights JavaScript client library. By using the sample app, you'll learn how to interact with Time Series Insights in JavaScript and visualize data through charts and graphs.

  1. Go to the Time Series Insights sample application. The following sign-in prompt appears:

    Time Series Insights client sample sign-in prompt

  2. Select Log in to enter or select your credentials. Use either an enterprise organization account (Azure Active Directory) or a personal account (Microsoft account).

    Time Series Insights client sample credentials prompt

  3. After you sign in, a page that displays charts populated with Time Series Insights data is shown. Your user account and the Log out option are visible in the upper right corner:

    Time Series Insights client sample main page after sign-in

Page source and structure

First, let's view the HTML and JavaScript source code of the rendered webpage:

  1. Open Developer Tools in your browser. Inspect the HTML elements that make up the current page (also known as the HTML or DOM tree).

  2. Expand the <head> and <body> elements and observe the following sections:

    • Under the <head> element, you'll find page metadata and dependencies that enable the app to run:

      • A <script> element that's used to reference the Azure Active Directory Authentication Library (ADAL) file adal.min.js. ADAL is a JavaScript library that provides OAuth 2.0 authentication (sign-in) and token acquisition for accessing APIs.
      • Multiple <link> elements for style sheets (also known as CSS) like sampleStyles.css and tsiclient.css. The style sheets control visual page styling details, such as colors, fonts, and spacing.
      • A <script> element that's used to reference the Time Series Insights JavaScript client library tsiclient.js. The page uses the library to call Time Series Insights service APIs and to render chart controls on the page.

      Note

    • Under the <body> element, you'll find <div> elements, which help define the layout of items on the page, and another <script> element:

      • The first <div> element specifies the Log in dialog box (id="loginModal").
      • The second <div> element acts as a parent for:
        • A header <div> element that's used for status messages and sign-in information near the top of the page (class="header").
        • A <div> element for the remainder of the page body elements, including the charts (class="chartsWrapper").
        • A <script> section that contains the JavaScript that's used to control the page.

    Time Series Insights Client sample with Developer Tools

  3. Expand the <div class="chartsWrapper"> element and you'll find more child <div> elements. These elements are used to position each chart control example. There are several pairs of <div> elements, one for each chart example:

    • The first (class="rowOfCardsTitle") element contains a descriptive title to summarize what the chart(s) illustrate. For example: Static Line Charts With Full-Size Legends.
    • The second (class="rowOfCards") element is a parent that contains additional child <div> elements that position the actual chart controls within a row.

    Body div elements

  4. Expand the <script type="text/javascript"> element that's directly below the <div class="chartsWrapper"> element. The beginning of the page-level JavaScript section is used to handle all of the page logic (authentication, calling Time Series Insights service APIs, rendering the chart controls, and more):

    Body script

Time Series Insights JavaScript client library concepts

The Time Series Insights client library (tsclient.js) provides abstractions for two important JavaScript functionalities:

  • Wrapper methods for calling the Time Series Insights Query APIs: REST APIs you can use to query for Time Series Insights data by using aggregate expressions. The methods are organized under the TsiClient.Server namespace of the library.

  • Methods for creating and populating several types of charting controls: Methods you can use to render the Time Series Insights aggregate data in a webpage. The methods are organized under the TsiClient.UX namespace of the library.

Through these simplifications, developers can more easily build UI graph and chart components that are powered with Time Series Insights data.

Authentication

The Time Series Insights sample application is a single-page app that has ADAL OAuth 2.0 user authentication support:

  1. When you use ADAL for authentication, the client app must be registered in Azure Active Directory (Azure AD). In fact, the single-page app is registered to use the OAuth 2.0 implicit grant flow.

  2. The application must specify some of the registration properties at runtime. The properties include the client GUID (clientId) and the redirect URI (postLogoutRedirectUri).

  3. Later, the app requests an access token from Azure AD. The access token is issued for a finite set of permissions for a specific service or API identifier (https://api.timeseries.azure.com). The token permissions are issued on behalf of the signed-in user. The identifier for the service or API is another property that's contained in the app's Azure AD registration.

  4. After ADAL returns the access token to the app, it's passed as a bearer token when it accesses the Time Series Insights service APIs.

    // START: AUTHENTICATION RELATED CODE USING ADAL.JS
        // Set up ADAL
        var authContext = new AuthenticationContext({
            clientId: '000000-000000-000000-000000',
            postLogoutRedirectUri: 'https://tsiapp.azurewebsites.net/',
            cacheLocation: 'localStorage'
        });
        
        if (authContext.isCallback(window.location.hash)) {
        
            // Handle redirect after token requests
            authContext.handleWindowCallback();
            var err = authContext.getLoginError();
            if (err) {
                // TODO: Handle errors signing in and getting tokens
                document.getElementById('api_response').textContent = err;
                document.getElementById('loginModal').style.display = "block";
            }
        
        } else {
            var user = authContext.getCachedUser();
            if (user) {
                document.getElementById('username').textContent = user.userName;
                
            } else {
                document.getElementById('username').textContent = 'Not signed in.';
            }
        }
        
        authContext.getTsiToken = function(){
            document.getElementById('api_response2').textContent = 'Getting tsi token...';
            
            // Get an access token to the Microsoft TSI API
            var promise = new Promise(function(resolve,reject){
                authContext.acquireToken(
                'https://api.timeseries.azure.com/',
                function (error, token) {
        
                    if (error || !token) {
                        // TODO: Handle error obtaining access token
                        document.getElementById('api_response').textContent = error;
                        document.getElementById('loginModal').style.display = "block";
                        document.getElementById('api_response2').textContent = '';
                        return;
                    }
        
                    // Use the access token
                    document.getElementById('api_response').textContent = '';
                    document.getElementById('api_response2').textContent = '';
                    document.getElementById('loginModal').style.display = "none";
                    resolve(token);
                    }
                );
            });
            
            return promise;
        }
    // END: AUTHENTICATION RELATED CODE USING ADAL.JS
    

Tip

To learn more about Microsoft-supported Azure AD authentication libraries, see the Azure Active Directory Authentication Library reference documentation.

Control identification

In the provided example, <div> elements are arranged in the parent <body> element to provide a sensible layout for the chart controls that render on the page.

Each <div> element specifies properties for the placement and visual attributes of chart controls. HTML element id properties serve as unique identifiers to bind to specific controls to render and update visualized data.

Aggregate expressions

The Time Series Insights client library APIs use aggregate expressions:

  • An aggregate expression provides the ability to construct one or more search terms.

  • The client APIs are designed to provide similar functionality to another demo app (the Time Series Insights explorer), which uses search span, where predicates, measures, and splitBy values.

  • Most client library APIs take an array of aggregate expressions that the service uses to build a Time Series Insights data query.

Call pattern

Populating and rendering chart controls follows a general pattern. You can observe the general pattern throughout the sample app, and can assist you when you use the client library:

  1. Declare an array to hold one or more Time Series Insights aggregate expressions:

    var aes =  [];
    
  2. Build 1 to n aggregate expression objects. Then, add them to the aggregate expression array:

    var ae = new tsiClient.ux.aggregateExpression(predicateObject, measureObject, measureTypes, searchSpan, splitByObject, color, alias, contextMenuActions);
    aes.push(ae);
    

    aggregateExpression parameters

    Parameter Description Example
    predicateObject The data filtering expression {predicateString: "Factory = 'Factory3'"}
    measureObject The property name of the measure that's used {property: 'Temperature', type: "Double"}
    measureTypes The aggregations of the measure property you want ['avg', 'min']
    searchSpan The duration and interval size of the aggregate expression {from: startDate, to: endDate, bucketSize: '2m'}
    splitByObject The string property you want to split by (optional: can be null) {property: 'Station', type: 'String'}
    color The color of the objects you want to render 'pink'
    alias A friendly name for the aggregate expression 'Factory3Temperature'
    contextMenuActions An array of actions to be bound to the time series objects in a visualization (optional) For more information, see Pop-up context menus.
  3. Call a Time Series Insights query by using the TsiClient.Server APIs to request the aggregate data:

    tsiClient.server.getAggregates(token, envFQDN, aeTsxArray);
    

    getAggregates parameters

    Parameter Description Example
    token The access token for the Time Series Insights API authContext.getTsiToken()
    For more information, see Authentication.
    envFQDN The fully qualified domain name (FQDN) for the Time Series Insights environment From the Azure portal. For example: 10000000-0000-0000-0000-100000000108.env.timeseries.azure.com.
    aeTsxArray An array of Time Series Insights query expressions Use the aes variable as described earlier: aes.map(function(ae){return ae.toTsx()}.
  4. Transform the compressed result that's returned from the Time Series Insights query into JSON for visualization:

    var transformedResult = tsiClient.ux.transformAggregatesForVisualization(result, aes);
    
  5. Create a chart control by using the TsiClient.UX APIs. Bind it to one of the <div> elements on the page:

    var barChart = new tsiClient.ux.BarChart(document.getElementById('chart3'));
    
  6. Populate the chart control with the transformed JSON data objects and render the control on the page:

    barChart.render(transformedResult, {grid: true, legend: 'compact', theme: 'light'}, aes);
    

Render controls

The Time Series Insights client library provides eight unique, out-of-the-box analytics controls:

  • line chart
  • pie chart
  • bar chart
  • heatmap
  • hierarchy controls
  • accessible grid
  • discrete event timelines
  • state transition timelines

Line chart, bar chart, and pie chart examples

Look at the demo code that's used to render some of the standard chart controls. Note the programming model and patterns for creating those controls. Specifically, examine the HTML under the // Example 3/4/5 comment, which renders controls with the HTML id values chart3, chart4, and chart5.

Recall from step 3 of the Page source and structure section that chart controls are arranged in rows on the page. Each chart control has a descriptive title row. In this example, the three charts are populated under the Multiple Chart Types From the Same Data title <div> element and are bound to the three <div> elements that are below the title:

<div class="rowOfCardsTitle">Multiple Chart Types From the Same Data</div>
<div class="rowOfCards">
    <div class="card" style="flex-shrink: 1; height: 100%; width: 30%;">
        <div style="color: black; background: white; border-bottom: 1px solid silver;" class="cardTitle">Factory Temps Split by Station as a Line Chart, Light Theme</div>
        <div class="cardChart" id="chart3"></div>
    </div>
    <div class="card" style="flex-shrink: 1; height: 100%; width: 30%;">
        <div class="cardTitle">Factory Temps Split by Station as a Bar Chart</div>
        <div class="cardChart" id="chart4"></div>
    </div>
    <div class="card" style="flex-shrink: 1; height: 100%; width: 30%;">
        <div style="color: black; background: white; border-bottom: 1px solid silver;" class="cardTitle">Factory Temps Split by Station as a Pie Chart, Light Theme</div>
        <div class="cardChart" id="chart5"></div>
    </div>
</div>

The following section of JavaScript code uses patterns that were outlined earlier: build Time Series Insights aggregate expressions, use them to query for Time Series Insights data, and then render the three charts. Three chart types are used from the tsiClient.ux namespace: LineChart, BarChart, and PieChart. The chart types are used to create and render the respective charts. All three charts can use the same aggregate expression data transformedResult:

// Example 3/4/5
var aggregateExpressions4 = [];
var startDate = new Date('2017-04-19T13:00:00Z');
var endDate = new Date(startDate.valueOf() + 1000*60*60*1);
aggregateExpressions4.push(new tsiClient.ux.AggregateExpression({predicateString: "Factory = 'Factory3'"}, {property: 'Temperature', type: "Double"}, ['avg', 'min', 'max'],
    { from: startDate, to: endDate, bucketSize: '2m' }, {property: 'Station', type: 'String'}, 'green', 'Factory3Temperature'));
aggregateExpressions4.push(new tsiClient.ux.AggregateExpression({predicateString: "Factory = 'Factory1'"}, {property: 'Temperature', type: "Double"}, ['min', 'avg', 'max'],
    { from: startDate, to: endDate, bucketSize: '3m' }, {property: 'Station', type: 'String'}, 'purple', 'Factory1Temp'));
authContext.getTsiToken().then(function(token){
    tsiClient.server.getAggregates(token, '10000000-0000-0000-0000-100000000108.env.timeseries.azure.com', aggregateExpressions4.map(function(ae){return ae.toTsx()})).then(function(result){
        var transformedResult = tsiClient.ux.transformAggregatesForVisualization(result, aggregateExpressions4);
        
        var lineChart = new tsiClient.ux.LineChart(document.getElementById('chart3'));
        lineChart.render(transformedResult, {grid: true, legend: 'compact', theme: 'light'}, aggregateExpressions4);
        
        var barChart =  new tsiClient.ux.BarChart(document.getElementById('chart4'));
        barChart.render(transformedResult, {grid: true, timestamp: '2017-04-19T13:00:00Z', legend: 'compact'}, aggregateExpressions4);

        var pieChart =  new tsiClient.ux.PieChart(document.getElementById('chart5'));
        pieChart.render(transformedResult, {grid: true, theme: 'light', timestamp: '2017-04-19T13:00:00Z', arcWidthRatio: .4, legend: 'compact'}, aggregateExpressions4);
    });
});        

The three charts appear as follows when rendered:

Multiple chart types from the same data

Advanced features

The Time Series Insights client library has several additional features that you can use to implement data visualizations creatively.

States and events

An advanced functionality is the ability to add state transitions and discrete events to charts. This feature is useful for highlighting incidents, alerting, and creating state switches (on/off switches, for example).

Look at the code surrounding the // Example 10 comment. The code renders a line control under the title Line Charts with Multiple Series Types and binds it to the <div> element with the HTML id value chart10.

The following steps describe the process:

  1. A structure named events4 is defined to hold the state-change elements to track. The structure contains:

    • A string key named Component States.
    • An array of value objects that represent the states. Each object includes:
      • A string key that contains a JavaScript ISO timestamp.
      • An array that contains the characteristics of the state: a color and a description.
  2. The events5 structure is defined for Incidents, which holds an array of the event elements to track. The array structure is the same shape as the structure that's outlined for events4.

  3. The line chart is rendered and passes in the two structures with the chart options parameters: events: and states:. Note the other option parameters for specifying a tooltip:, theme:, or grid:.

//Example 10
var startDate = new Date('2017-04-19T13:00:00Z');
var endDate = new Date(startDate.valueOf() + 1000*60*60*1);

var events4 = {"Component States" : [
    {
        '2017-04-19T13:05:00Z' : {
            'color': 'lightblue',
            'description' : 'Cooling fan on'
        }
    },
    {
        '2017-04-19T13:27:00Z' : {
            'color': 'yellow',
            'description' : 'Filling tank at maximum pressure'
        }
    },
    {
        '2017-04-19T13:47:00Z' : {
            'color': 'red',
            'description' : 'Pressing machine overheated'
        }
    }
]};

var events5 = {"Incidents" : [
    {
        '2017-04-19T13:12:00Z' : {
            'color': 'Yellow',
            'description' : 'Recoverable failure'
        }
    },
    {
        '2017-04-19T13:25:00Z' : {
            'color': 'red',
            'description' : 'Catastrophic failure'
        }
    },
        {
        '2017-04-19T13:47:00Z' : {
            'color': 'purple',
            'description' : 'Informational event'
        }
    }
]}

authContext.getTsiToken().then(function(token){
    tsiClient.server.getAggregates(token, '10000000-0000-0000-0000-100000000108.env.timeseries.azure.com', aggregateExpressions4.map(function(ae){return ae.toTsx()})).then(function(result){
        var transformedResult = tsiClient.ux.transformAggregatesForVisualization(result, aggregateExpressions4);
        var lineChart = new tsiClient.ux.LineChart(document.getElementById('chart10'));
        lineChart.render(transformedResult, {tooltip: true, grid: true, theme: "dark", events: [events5], states: [events4]}, aggregateExpressions4);
    });
}); 

The diamond markers/pop-up windows that are used to indicate incidents and the colored bars/pop-up windows along the time scale indicate state changes:

Line charts with multiple series types

Pop-up context menus

Another advanced functionality is the ability to create custom context menus (right-click pop-up menus). Custom context menus are useful for enabling actions and logical next steps within the scope of your application.

Look at the code around the // Example 13/14/15 comment. This code initially renders a line chart under the title Line Chart with Context Menu to Create Pie/Bar Chart. The chart is bound to the <div> element with the HTML id value chart13.

By using context menus, the line chart provides the capability to dynamically create a pie and bar chart that are bound to <div> elements with the IDs chart14 and chart15. Both the pie chart and the bar chart also use context menus to enable their own features: the ability to copy data from the pie chart to the bar chart and to print the bar chart data to the browser console window, respectively.

The following steps describe the process:

  1. A series of custom actions are defined. Each action contains an array with one or more elements. Each element defines a single context menu item:

    • barChartActions: This action defines the context menu for the pie chart, which contains one element to define a single item:

      • name: The text that's used for the menu item: "Print parameters to console."
      • action: The action that's associated with the menu item. The action is always an anonymous function that takes three arguments that are based on the aggregate expression that's used to create the chart. In this case, the arguments are written to the browser console window:
        • ae: The aggregate expression array.
        • splitBy: The splitBy value.
        • timestamp: The timestamp.
    • pieChartActions: This action defines the context menu for the bar chart, which contains one element to define a single item. The shape and schema is the same as the barChartActions element described earlier, but the action function is dramatically different: it instantiates and renders the bar chart. The ae argument is used to specify the aggregate expression array that's passed at runtime when the menu item opens. The function also sets the ae.contextMenu property with the barChartActions context menu.

    • contextMenuActions: This action defines the context menu for the line chart, which contains three elements to define three menu items. The shape and schema for each element is the same as the elements that were described earlier. Just like the barChartActions element, the first item writes the three function arguments to the browser console window. Similar to the pieChartActions element, the second two items instantiate and render the pie chart and bar chart, respectively. The second two items also set their ae.contextMenu properties with the pieChartActions and barChartActions context menus, respectively.

  2. Two aggregate expressions are pushed onto the aes aggregate expression array. They specify the contextMenuActions array for each item. These expressions are used with the line chart control.

  3. Only the line chart is initially rendered, from which both the pie chart and the bar chart can be rendered at runtime.

// example 13/14/15
// Line chart with a context menu which generates pie and bar chart
var aggregateExpressions9 = [];
var pieChart2 = new tsiClient.ux.PieChart(document.getElementById('chart14'));
var barChart2 = new tsiClient.ux.BarChart(document.getElementById('chart15'));

var barChartActions = [{
    name: "Print parameters to console",
    action: function(ae, splitBy, timestamp) {
        console.log(ae);
        console.log(splitBy);
        console.log(timestamp);
    }
}];

var pieChartActions = [{
    name: "Copy to Bar Chart",
    action: function(ae, splitBy, timestamp) {
        ae.contextMenu = barChartActions;
        authContext.getTsiToken().then(function(token){
            tsiClient.server.getAggregates(token, '10000000-0000-0000-0000-100000000108.env.timeseries.azure.com', [ae].map(function(ae){return ae.toTsx()})).then(function(result){
                var transformedResult = tsiClient.ux.transformAggregatesForVisualization(result, [ae]); 
                barChart2.render(transformedResult, {grid: true, theme: 'light', timestamp: timestamp, arcWidthRatio: .6}, [ae]);
            });
        });
    }
}]

var contextMenuActions = [{
    name: "Print parameters to console",
    action: function(ae, splitBy, timestamp) {
        console.log(ae);
        console.log(splitBy);
        console.log(timestamp);
    }
}, 
{
    name: "Plot as a Pie Chart",
    action: function(ae, splitBy, timestamp) {
        ae.contextMenu = pieChartActions;
        authContext.getTsiToken().then(function(token){
            tsiClient.server.getAggregates(token, '10000000-0000-0000-0000-100000000108.env.timeseries.azure.com', [ae].map(function(ae){return ae.toTsx()})).then(function(result){
                var transformedResult = tsiClient.ux.transformAggregatesForVisualization(result, [ae]); 
                pieChart2.render(transformedResult, {grid: true, theme: 'light', timestamp: timestamp, arcWidthRatio: .6}, [ae]);
            });
        });
    }
}, {
    name: "Plot as a Bar Chart",
    action: function(ae, splitBy, timestamp) {
        ae.contextMenu = barChartActions;
        authContext.getTsiToken().then(function(token){
            tsiClient.server.getAggregates(token, '10000000-0000-0000-0000-100000000108.env.timeseries.azure.com', [ae].map(function(ae){return ae.toTsx()})).then(function(result){
                var transformedResult = tsiClient.ux.transformAggregatesForVisualization(result, [ae]); 
                barChart2.render(transformedResult, {grid: true, theme: 'light', timestamp: timestamp }, [ae]);
            });
        });
    }
}];

aggregateExpressions9.push(new tsiClient.ux.AggregateExpression({predicateString: "Factory = 'Factory3'"}, {property: 'Temperature', type: "Double"}, ['avg', 'min'],
    { from: startDate, to: endDate, bucketSize: '2m' }, {property: 'Station', type: 'String'}, 'pink', 'Factory3Temperature', contextMenuActions));
aggregateExpressions9.push(new tsiClient.ux.AggregateExpression({predicateString: "Factory = 'Factory1'"}, {property: 'Temperature', type: "Double"}, ['avg', 'min'],
    { from: startDate, to: endDate, bucketSize: '2m' }, {property: 'Station', type: 'String'}, 'green', 'Factory1Temperature', contextMenuActions));

var brushActions = [{
    name: "Print parameters to console",
    action: function(fromTime, toTime) {
        console.log(fromTime);
        console.log(toTime);
    }
}];

authContext.getTsiToken().then(function(token){
    tsiClient.server.getAggregates(token, '10000000-0000-0000-0000-100000000108.env.timeseries.azure.com', aggregateExpressions9.map(function(ae){return ae.toTsx()})).then(function(result){
        var transformedResult = tsiClient.ux.transformAggregatesForVisualization(result, aggregateExpressions9);
        var lineChart = new tsiClient.ux.LineChart(document.getElementById('chart13'));
        lineChart.render(transformedResult, {theme: "light", legend: "compact", brushContextMenuActions: brushActions, grid: true, snapBrush: true}, aggregateExpressions9);
    });
});

The following screenshot shows the charts with their respective pop-up context menus. The pie chart and bar chart were created dynamically by using the line chart context menu options.

Line chart with context menu to create pie chart and bar chart

Brushes

You can use brushes to scope a time range to define actions like zoom and explore.

The code that's used to illustrate brushes is shown in the Line Chart with Context Menu to Create Pie/Bar Chart example that describes pop-up context menus.

  • Brush actions are similar to a context menu in that they define a series of custom actions for the brush. Each action contains an array that has one or more elements. Each element defines a single context menu item:

    • name: The text that's used for the menu item: "Print parameters to console."
    • action: The action that's associated with the menu item, which is always an anonymous function that takes two arguments. In this case, the arguments are written to the browser console window:
      • fromTime: The from timestamp of the brush selection.
      • toTime: The to timestamp of the brush selection.
  • Brush actions are added as another chart option property. The brushContextMenuActions: brushActions property is passed to the linechart.Render call.

var brushActions = [{
    name: "Print parameters to console",
    action: function(fromTime, toTime) {
        console.log(fromTime);
        console.log(toTime);
    }
}];

authContext.getTsiToken().then(function(token){
    tsiClient.server.getAggregates(token, '10000000-0000-0000-0000-100000000108.env.timeseries.azure.com', aggregateExpressions9.map(function(ae){return ae.toTsx()})).then(function(result){
        var transformedResult = tsiClient.ux.transformAggregatesForVisualization(result, aggregateExpressions9);
        var lineChart = new tsiClient.ux.LineChart(document.getElementById('chart13'));
        lineChart.render(transformedResult, {theme: "light", legend: "compact", brushContextMenuActions: brushActions, grid: true, snapBrush: true}, aggregateExpressions9);
    });
});

Line chart with context menu to create pie chart and bar chart by using brushes

Next steps

In this tutorial, you learned how to:

  • Sign in and explore the Time Series Insights sample application and its source
  • Use APIs in the Time Series Insights JavaScript client library
  • Use JavaScript to create and populate chart controls with Time Series Insights data

The Time Series Insights sample application uses a demo dataset. To learn how you can create your own Time Series Insights environment and dataset, read the following article:

Or, view the Time Series Insights sample application source files:

Read the Time Series Insights client API reference documentation: