Trend Lines

The TrendLine class extends the regular Series class to provide a calculated series based on the data and parameters you select.

To add trend lines to a chart, follow these steps:

  1. Create one or more TrendLine objects,
  2. Configure the TrendLine objects as you would a regular series, setting their binding, chartType, and style properties for example, and
  3. Set the TrendLine's fitType and order properties to determine the type of trend line you want to create.
import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; import * as wjChart from '@grapecity/wijmo.chart'; import * as wjChartAnalytics from '@grapecity/wijmo.chart.analytics'; import * as wjInput from '@grapecity/wijmo.input'; import { getData } from './data'; // document.readyState === 'complete' ? init() : window.onload = init; // function init() { // create the chart let theChart = new wjChart.FlexChart('#theChart', { itemsSource: getData(), chartType: 'Scatter', axisY: { axisLine: true }, bindingX: 'x', series: [ { name: 'Raw Data', binding: 'y' } ] }); // // show the equation on the chart let equation = document.getElementById('equation'); // // create a TrendLine and add it to the Chart series collection let trendLine = new wjChartAnalytics.TrendLine(); trendLine.binding = 'y'; trendLine.style = { stroke: 'darkred', strokeWidth: 3 }; trendLine.visibility = wjChart.SeriesVisibility.Hidden; theChart.series.push(trendLine); // // select trendline order let order = new wjInput.InputNumber('#order', { value: trendLine.order, step: 1, min: 1, max: 6, valueChanged: (s) => { if (s.value >= s.min && s.value <= s.max) { trendLine.order = s.value; showEquation(); } } }); // // select fit type let fitType = new wjInput.ComboBox('#fitType', { isRequired: false, placeholder: 'None', textChanged: (s) => { trendLine.name = s.text; if (s.text) { // show trendline trendLine.fitType = s.text; trendLine.visibility = wjChart.SeriesVisibility.Visible; } else { // hide trendline trendLine.visibility = wjChart.SeriesVisibility.Hidden; } switch (s.text) { // enable/disable order input case 'Polynomial': case 'Fourier': order.isDisabled = false; break; default: order.isDisabled = true; break; } showEquation(); }, itemsSource: 'Linear,Exponential,Logarithmic,Power,Fourier,Polynomial,MinX,MinY,MaxX,MaxY,AverageX,AverageY'.split(',') }); // // show updated equation on a timeOut since the TrendLine update is async function showEquation() { equation.innerHTML = ''; setTimeout(() => equation.innerHTML = trendLine.getEquation(), 100); } // // randomize the data document.querySelector('#btnRandomize').addEventListener('click', () => { theChart.itemsSource = getData(); showEquation(); }); } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexChart Trendlines</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div class="container-fluid"> <label for="fitType">Trendline Type: </label> <div id="fitType"></div><br /> <label for="order">Order: </label> <div id="order"></div><br /> <label>Equation: </label> <div id="equation" class="equation"></div><br /> <label for="btnRandomize">Randomize Data</label> <button id="btnRandomize" class="btn btn-default"> Go </button> <div id="theChart"></div> </div> </body> </html> // data sources export function getData() { let arr = [], cnt = 50, a = Math.random(), b = Math.random(); // for (let i = 1; i < cnt; i++) { arr.push({ x: i, y: a + i * b + i * Math.random() }); } // return arr; } .wj-flexchart { height: 250px; margin: 10px 0; } .wj-control { margin-bottom: 3px; } label { width: 120px; text-align: right; } .equation { display: inline-block; font-style: italic; font-size: 80%; } .wj-combobox, .wj-inputnumber { width: 120px; margin-right: 12px; } body { margin-bottom: 24pt; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; // import { Component, Inject, enableProdMode, NgModule, ViewChild } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BrowserModule } from '@angular/platform-browser'; import { WjInputModule } from '@grapecity/wijmo.angular2.input'; import { WjChartModule } from '@grapecity/wijmo.angular2.chart'; import { WjChartAnalyticsModule } from '@grapecity/wijmo.angular2.chart.analytics'; import { DataService } from './app.data'; import * as wjInput from '@grapecity/wijmo.input'; import * as wjChart from '@grapecity/wijmo.chart'; import * as wjChartAnalytics from '@grapecity/wijmo.chart.analytics'; // @Component({ selector: 'app-component', templateUrl: 'src/app.component.html' }) export class AppComponent { data: any[]; cbData: string[]; order: number; eqEle: HTMLDivElement; @ViewChild('orderIpt') orderIpt: wjInput.InputNumber; @ViewChild('trendline') trendLine: wjChartAnalytics.TrendLine; // constructor(@Inject(DataService) private dataService: DataService) { this.data = dataService.getData(); this.cbData = dataService.getComboData(); this.order = 2; } // showEquation() { if(!this.eqEle){ this.eqEle = <HTMLDivElement>document.getElementById('equation'); } this.eqEle.innerHTML = ''; setTimeout(() => this.eqEle.innerHTML = this.trendLine.getEquation(), 100); } // randomData() { this.data = this.dataService.getData(); this.showEquation(); } // valueChanged(s: wjInput.InputNumber) { if (s.value >= s.min && s.value <= s.max) { this.order = s.value; this.showEquation(); } } // textChanged(s: wjInput.ComboBox) { let trendLine = this.trendLine; if(!trendLine) { return; } trendLine.name = s.text; if (s.text) { // show trendline trendLine.fitType = <any>s.text; trendLine.visibility = wjChart.SeriesVisibility.Visible; } else { // hide trendline trendLine.visibility = wjChart.SeriesVisibility.Hidden; } switch (s.text) { // enable/disable order input case 'Polynomial': case 'Fourier': this.orderIpt.isDisabled = false; break; default: this.orderIpt.isDisabled = true; break; } this.showEquation(); } } // @NgModule({ imports: [WjInputModule, WjChartModule, WjChartAnalyticsModule, BrowserModule], declarations: [AppComponent], providers: [DataService], bootstrap: [AppComponent] }) export class AppModule { } // enableProdMode(); // Bootstrap application with hash style navigation and global services. platformBrowserDynamic().bootstrapModule(AppModule); <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexChart Trendlines</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Polyfills --> <script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/zone.js/dist/zone.min.js"></script> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.js"></script> <script src="systemjs.config.js"></script> <script> // workaround to load 'rxjs/operators' from the rxjs bundle System.import('rxjs').then(function (m) { System.set(SystemJS.resolveSync('rxjs/operators'), System.newModule(m.operators)); System.import('./src/app.component'); }); </script> </head> <body> <app-component></app-component> </body> </html> <div class="container-fluid"> <div class="form-group"> <label for="fitType">Trendline Type: </label> <wj-combo-box #cb [isRequired]="false" placeholder="None" [itemsSource]="cbData" (textChanged)="textChanged(cb)"></wj-combo-box><br /> <label for="order">Order: </label> <wj-input-number #orderIpt [step]="1" [min]="1" [max]="6" [value]="2" (valueChanged)="valueChanged(orderIpt)"></wj-input-number><br /> <label for="equation">Equation: </label> <div id="equation" class="equation"></div><br> <label for="btnRandomize">Randomize Data</label> <button id="btnRandomize" class="btn btn-default" (click)="randomData()"> Go </button> <wj-flex-chart [itemsSource]="data" chartType="Scatter" bindingX="x"> <wj-flex-chart-axis wjProperty="axisY" [axisLine]="true"></wj-flex-chart-axis> <wj-flex-chart-series name="Raw Data" binding="y"></wj-flex-chart-series> <wj-flex-chart-trend-line #trendline binding="y" [order]="order" [style]="{stroke:'darkred',strokeWidth:3}" visibility="Hidden"></wj-flex-chart-trend-line> </wj-flex-chart> </div> </div> import { Injectable } from '@angular/core'; // @Injectable() export class DataService { getData() { let arr = [], cnt = 50, a = Math.random(), b = Math.random(); // for (let i = 1; i < cnt; i++) { arr.push({ x: i, y: a + i * b + i * Math.random() }); } // return arr; } // getComboData() { return 'Linear,Exponential,Logarithmic,Power,Fourier,Polynomial,MinX,MinY,MaxX,MaxY,AverageX,AverageY'.split(','); } } .wj-flexchart { height: 250px; margin: 10px 0; } .wj-control { margin-bottom: 3px; } label { width: 120px; text-align: right; } .equation { display: inline-block; font-style: italic; font-size: 80%; } .wj-combobox, .wj-inputnumber { width: 120px; margin-right: 12px; } body { margin-bottom: 24pt; } <template> <div class="container-fluid"> <div class="form-group"> <label for="fitType">Trendline Type: </label> <wj-combo-box :isRequired="false" placeholder="None" :itemsSource="comboData" :textChanged="textChanged" :initialized="initializeCombo"></wj-combo-box><br /> <label for="order">Order: </label> <wj-input-number :step="1" :min="1" :max="6" :value="order" :valueChanged="orderChanged" :initialized="initializeInput"></wj-input-number><br /> <label>Equation: </label> <div id="equation" class="equation"></div><br /> <label for="btnRandomize">Randomize Data</label> <button id="btnRandomize" class="btn btn-default" v-on:click="randomData"> Go </button> <wj-flex-chart :itemsSource="data" chartType="Scatter" bindingX="x" :initialized="initializeChart"> <wj-flex-chart-axis wjProperty="axisY" :axisLine="true"></wj-flex-chart-axis> <wj-flex-chart-series name="Raw Data" binding="y"></wj-flex-chart-series> <wj-flex-chart-trend-line binding="y" :order="order" :style="{stroke:'darkred',strokeWidth:3}"></wj-flex-chart-trend-line> </wj-flex-chart> </div> </div> </template> <script> import "@grapecity/wijmo.styles/wijmo.css"; import 'bootstrap.css'; import Vue from 'vue'; import '@grapecity/wijmo.vue2.core'; import '@grapecity/wijmo.vue2.input'; import '@grapecity/wijmo.vue2.chart'; import '@grapecity/wijmo.vue2.chart.analytics'; import { getData } from './data'; import * as wjChart from '@grapecity/wijmo.chart'; let App = Vue.extend({ name: 'app', data: function () { return { data: getData(), comboData: 'Linear,Exponential,Logarithmic,Power,Fourier,Polynomial,MinX,MinY,MaxX,MaxY,AverageX,AverageY'.split(','), order: 2 } }, mounted: function() { this.eqEle = document.querySelector('#equation'); this.reset(this.combo.selectedValue); }, methods: { initializeInput: function(flex) { this.orderIpt = flex; }, initializeCombo: function(flex) { this.combo = flex; }, initializeChart: function(flex) { this.theChart = flex; this.trendLine = flex.series[1]; }, orderChanged: function(s) { if (s.value >= s.min && s.value <= s.max) { this.order = s.value; this.showEquation(); } }, showEquation: function() { if(this.eqEle) { this.eqEle.innerHTML = ''; setTimeout(() => this.eqEle.innerHTML = this.trendLine.getEquation(), 100); } }, randomData: function() { this.data = getData(); this.showEquation(); }, textChanged: function(s) { this.reset(s.text); }, reset: function(text) { let trendLine = this.trendLine; if(!trendLine) { return; } trendLine.name = text; if (text) { // show trendline trendLine.fitType = text; trendLine.visibility = wjChart.SeriesVisibility.Visible; } else { // hide trendline trendLine.visibility = wjChart.SeriesVisibility.Hidden; } switch (text) { // enable/disable order input case 'Polynomial': case 'Fourier': this.orderIpt.isDisabled = false; break; default: this.orderIpt.isDisabled = true; break; } this.showEquation(); } } }) new Vue({ render: h => h(App) }).$mount('#app'); </script> <style> .wj-flexchart { height: 250px; margin: 10px 0; } .wj-control { margin-bottom: 3px; } label { width: 120px; text-align: right; } .equation { display: inline-block; font-style: italic; font-size: 80%; } .wj-combobox, .wj-inputnumber { width: 120px; margin-right: 12px; } body { margin-bottom: 24pt; } </style> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexChart Trendlines</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app.vue'); </script> </head> <body> <div id="app"></div> </body> </html> export function getData() { let arr = [], cnt = 50, a = Math.random(), b = Math.random(); // for (let i = 1; i < cnt; i++) { arr.push({ x: i, y: a + i * b + i * Math.random() }); } // return arr; } import "@grapecity/wijmo.styles/wijmo.css"; import "bootstrap.css"; import "./app.css"; // import * as React from 'react'; import * as ReactDOM from 'react-dom'; // import * as wjcChart from "@grapecity/wijmo.chart"; import * as wjInput from '@grapecity/wijmo.react.input'; import * as wjChart from "@grapecity/wijmo.react.chart"; import * as wjChartAnalysis from "@grapecity/wijmo.react.chart.analytics"; import { getData } from "./data"; class App extends React.Component { constructor(props) { super(props); this.state = { data: getData(), comboData: 'Linear,Exponential,Logarithmic,Power,Fourier,Polynomial,MinX,MinY,MaxX,MaxY,AverageX,AverageY'.split(','), order: 2 }; } render() { return <div className="container-fluid"> <div className="form-group"> <label htmlFor="fitType">Trendline Type: </label> <wjInput.ComboBox isRequired={false} placeholder="None" itemsSource={this.state.comboData} textChanged={this.textChanged.bind(this)} initialized={this.initializeCombo.bind(this)}></wjInput.ComboBox><br /> <label htmlFor="order">Order: </label> <wjInput.InputNumber step={1} min={1} max={6} value={this.state.order} valueChanged={this.orderChanged.bind(this)} initialized={this.initializeInput.bind(this)}></wjInput.InputNumber><br /> <label>Equation: </label> <div id="equation" className="equation"></div><br /> <label htmlFor="btnRandomize">Randomize Data</label> <button id="btnRandomize" className="btn btn-default" onClick={this.randomData.bind(this)}> Go </button> <wjChart.FlexChart itemsSource={this.state.data} chartType="Scatter" bindingX="x" initialized={this.initializeChart.bind(this)}> <wjChart.FlexChartAxis wjProperty="axisY" axisLine={true}></wjChart.FlexChartAxis> <wjChart.FlexChartSeries name="Raw Data" binding="y"></wjChart.FlexChartSeries> <wjChartAnalysis.FlexChartTrendLine binding="y" order={this.state.order} style={{ stroke: 'darkred', strokeWidth: 3 }}> </wjChartAnalysis.FlexChartTrendLine> </wjChart.FlexChart> </div> </div>; } componentDidMount() { this.eqEle = document.querySelector('#equation'); this.reset(this.combo.selectedValue); } initializeInput(flex) { this.orderIpt = flex; } initializeCombo(flex) { this.combo = flex; } initializeChart(flex) { this.trendLine = flex.series[1]; } orderChanged(s) { if (s.value >= s.min && s.value <= s.max) { this.setState({ order: s.value }); this.showEquation(); } } showEquation() { if (this.eqEle) { this.eqEle.innerHTML = ''; setTimeout(() => this.eqEle.innerHTML = this.trendLine.getEquation(), 100); } } randomData() { this.setState({ data: getData() }); this.showEquation(); } textChanged(s) { this.reset(s.text); } reset(text) { let trendLine = this.trendLine; if (!trendLine) { return; } trendLine.name = text; if (text) { // show trendline trendLine.fitType = text; trendLine.visibility = wjcChart.SeriesVisibility.Visible; } else { // hide trendline trendLine.visibility = wjcChart.SeriesVisibility.Hidden; } switch (text) { // enable/disable order input case 'Polynomial': case 'Fourier': this.orderIpt.isDisabled = false; break; default: this.orderIpt.isDisabled = true; break; } this.showEquation(); } } ReactDOM.render(<App />, document.getElementById('app')); <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Grapecity Wijmo OLAP Pivot Chart Overview</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div id="app"></div> </body> </html> .wj-flexchart { height: 250px; margin: 10px 0; } .wj-control { margin-bottom: 3px; } label { width: 120px; text-align: right; } .equation { display: inline-block; font-style: italic; font-size: 80%; } .wj-combobox, .wj-inputnumber { width: 120px; margin-right: 12px; } body { margin-bottom: 24pt; } export function getData() { let arr = [], cnt = 50, a = Math.random(), b = Math.random(); // for (let i = 1; i < cnt; i++) { arr.push({ x: i, y: a + i * b + i * (Math.random() - .5) }); } // return arr; }