Ordered Data Copy Link
import { Component } from "@angular/core";
import { AgCharts } from "ag-charts-angular";
import {
AgCartesianAxisOptions,
AgCartesianChartOptions,
AgCartesianSeriesOptions,
AnimationModule,
AreaSeriesModule,
BarSeriesModule,
CandlestickSeriesModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NavigatorModule,
NumberAxisModule,
OhlcSeriesModule,
OrdinalTimeAxisModule,
RangeAreaSeriesModule,
RangeBarSeriesModule,
TimeAxisModule,
UnitTimeAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";
ModuleRegistry.registerModules([
AnimationModule,
AreaSeriesModule,
BarSeriesModule,
CandlestickSeriesModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
NavigatorModule,
NumberAxisModule,
OhlcSeriesModule,
OrdinalTimeAxisModule,
RangeAreaSeriesModule,
RangeBarSeriesModule,
TimeAxisModule,
UnitTimeAxisModule,
ZoomModule,
ContextMenuModule,
]);
@Component({
selector: "my-app",
standalone: true,
imports: [AgCharts],
template: `<div class="example-controls">
<div class="controls-row">
<select (change)="setSeries($event.target.value)">
<option value="area">Area</option>
<option value="bar">Bar</option>
<option value="line" selected="">Line</option>
<option value="range-area">Range Area</option>
<option value="range-bar">Range Bar</option>
<option value="candlestick">Candlestick</option>
<option value="ohlc">OHLC</option>
</select>
<select (change)="setAxes($event.target.value)">
<option value="time">Continuous Time</option>
<option value="ordinal-time">Ordinal Time</option>
<option value="ordinal-time-parent" selected="">Ordinal Time (Parent Level)</option>
<option value="unit-time">Unit Time</option>
</select>
<button (click)="setData(1e3)">1k</button>
<button (click)="setData(1e4)">10k</button>
<button (click)="setData(1e5)">100k</button>
<button (click)="setData(1e6)">1m</button>
</div>
</div>
<ag-charts
[options]="options"
></ag-charts>
`,
})
export class AppComponent {
public options;
constructor() {
this.options = {
data: getData(1e4),
animation: { enabled: false },
zoom: {
enabled: true,
anchorPointX: "pointer",
anchorPointY: "pointer",
autoScaling: {
enabled: true,
},
},
navigator: {
enabled: true,
miniChart: {
enabled: true,
},
},
series: [
{
type: "line",
xKey: "timestamp",
yKey: "close",
},
],
axes: {
x: {
type: "ordinal-time",
parentLevel: { enabled: true },
},
},
};
}
setSeries = (type: string) => {
const options = clone(this.options);
let series: AgCartesianSeriesOptions;
switch (type) {
case "bar":
case "area":
case "line":
series = {
type,
xKey: "timestamp",
yKey: "close",
};
break;
case "range-area":
case "range-bar":
series = {
type,
xKey: "timestamp",
yLowKey: "low",
yHighKey: "high",
};
break;
case "candlestick":
case "ohlc":
series = {
type,
xKey: "timestamp",
lowKey: "low",
highKey: "high",
openKey: "open",
closeKey: "close",
};
break;
default:
return;
}
options.series = [series];
this.options = options;
};
setAxes = (type: string) => {
const options = clone(this.options);
let axis: AgCartesianAxisOptions;
switch (type) {
case "time":
axis = {
type,
nice: false,
};
break;
case "ordinal-time":
case "unit-time":
axis = {
type,
};
break;
case "ordinal-time-parent":
axis = {
type: "ordinal-time",
parentLevel: { enabled: true },
};
break;
default:
return;
}
options.axes = { x: axis };
this.options = options;
};
setData = (points: number) => {
const options = clone(this.options);
options.data = getData(points);
this.options = options;
};
}
const startPrice = 100;
const maxDailyPriceChange = 5;
const maxRangeDelta = 1;
function sfc32(a: number, b: number, c: number, d: number) {
return function () {
a >>>= 0;
b >>>= 0;
c >>>= 0;
d >>>= 0;
let t = (a + b) | 0;
a = b ^ (b >>> 9);
b = (c + (c << 3)) | 0;
c = (c << 21) | (c >>> 11);
d = (d + 1) | 0;
t = (t + d) | 0;
c = (c + t) | 0;
return (t >>> 0) / 4294967296;
};
}
function seedRandom(seed = 1337): () => number {
const realSeed = seed ^ 0xdeadbeef; // 32-bit seed with optional XOR value
// Pad seed with Phi, Pi and E.
// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
return sfc32(0x9e3779b9, 0x243f6a88, 0xb7e15162, realSeed);
}
export function getData(days: number) {
let currentPrice = startPrice;
const random = seedRandom();
return Array.from({ length: days }, (_, i) => {
// Note time is reversed
const close = currentPrice;
const open = close + (random() * 2 - 1) * maxDailyPriceChange;
currentPrice = open;
const high = Math.max(open, close) + random() * maxRangeDelta;
const low = Math.min(open, close) - random() * maxRangeDelta;
const timestamp = new Date(2024, 0, 1, -i);
return { timestamp, open, close, high, low };
}).reverse();
}
// Angular entry point file
import '@angular/compiler';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
bootstrapApplication(AppComponent);
Stacked Data Copy Link
import { Component } from "@angular/core";
import { AgCharts } from "ag-charts-angular";
import {
AgCartesianAxisOptions,
AgCartesianChartOptions,
AgCartesianSeriesOptions,
AnimationModule,
AreaSeriesModule,
BarSeriesModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NavigatorModule,
NumberAxisModule,
OrdinalTimeAxisModule,
TimeAxisModule,
UnitTimeAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";
ModuleRegistry.registerModules([
AnimationModule,
AreaSeriesModule,
BarSeriesModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
NavigatorModule,
NumberAxisModule,
OrdinalTimeAxisModule,
TimeAxisModule,
UnitTimeAxisModule,
ZoomModule,
ContextMenuModule,
]);
@Component({
selector: "my-app",
standalone: true,
imports: [AgCharts],
template: `<div class="example-controls">
<div class="controls-row">
<select (change)="setSeries($event.target.value)">
<option value="area" selected="">Area</option>
<option value="bar">Bar</option>
<option value="line">Line</option>
</select>
<select (change)="setAxes($event.target.value)">
<option value="time">Continuous Time</option>
<option value="ordinal-time">Ordinal Time</option>
<option value="ordinal-time-parent" selected="">Ordinal Time (Parent Level)</option>
<option value="unit-time">Unit Time</option>
</select>
<button (click)="setData(1e3)">1k</button>
<button (click)="setData(1e4)">10k</button>
<button (click)="setData(1e5)">100k</button>
<button (click)="setData(1e6)">1m</button>
</div>
</div>
<ag-charts
[options]="options"
></ag-charts>
`,
})
export class AppComponent {
public options;
constructor() {
this.options = {
data: getData(1e4),
animation: { enabled: false },
zoom: {
enabled: true,
anchorPointX: "pointer",
anchorPointY: "pointer",
autoScaling: {
enabled: true,
},
},
navigator: {
enabled: true,
miniChart: {
enabled: true,
},
},
series: [
{
type: "area",
xKey: "timestamp",
yKey: "petrol",
stacked: true,
},
{
type: "area",
xKey: "timestamp",
yKey: "diesel",
stacked: true,
},
],
axes: {
x: {
type: "ordinal-time",
parentLevel: { enabled: true },
},
},
};
}
setSeries = (type: string) => {
const options = clone(this.options);
let series: AgCartesianSeriesOptions[];
switch (type) {
case "bar":
case "area":
case "line":
series = [
{
type,
xKey: "timestamp",
yKey: "petrol",
stacked: true,
},
{
type,
xKey: "timestamp",
yKey: "diesel",
stacked: true,
},
];
break;
default:
return;
}
options.series = series;
this.options = options;
};
setAxes = (type: string) => {
const options = clone(this.options);
let axis: AgCartesianAxisOptions;
switch (type) {
case "time":
axis = {
type,
nice: false,
};
break;
case "ordinal-time":
case "unit-time":
axis = {
type,
};
break;
case "ordinal-time-parent":
axis = {
type: "ordinal-time",
parentLevel: { enabled: true },
};
break;
default:
return;
}
options.axes = { x: axis };
this.options = options;
};
setData = (points: number) => {
const options = clone(this.options);
options.data = getData(points);
this.options = options;
};
}
const startPetrol = 100;
const startDiesel = 50;
const maxDailyPriceChange = 0.5;
function sfc32(a: number, b: number, c: number, d: number) {
return function () {
a >>>= 0;
b >>>= 0;
c >>>= 0;
d >>>= 0;
let t = (a + b) | 0;
a = b ^ (b >>> 9);
b = (c + (c << 3)) | 0;
c = (c << 21) | (c >>> 11);
d = (d + 1) | 0;
t = (t + d) | 0;
c = (c + t) | 0;
return (t >>> 0) / 4294967296;
};
}
function seedRandom(seed = 1337): () => number {
const realSeed = seed ^ 0xdeadbeef; // 32-bit seed with optional XOR value
// Pad seed with Phi, Pi and E.
// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
return sfc32(0x9e3779b9, 0x243f6a88, 0xb7e15162, realSeed);
}
export function getData(days: number) {
const random = seedRandom();
let petrol = startPetrol;
let diesel = startDiesel;
return Array.from({ length: days }, (_, i) => {
// Note time is reversed
petrol += (random() * 2 - 1) * maxDailyPriceChange;
diesel += (random() * 2 - 1) * maxDailyPriceChange;
const timestamp = new Date(2024, 0, 1, -i);
return { timestamp, petrol, diesel };
}).reverse();
}
// Angular entry point file
import '@angular/compiler';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
bootstrapApplication(AppComponent);
Bubble, Scatter Copy Link
import { Component } from "@angular/core";
import { AgCharts } from "ag-charts-angular";
import {
AgCartesianChartOptions,
AgCartesianSeriesOptions,
AnimationModule,
BubbleSeriesModule,
CategoryAxisModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
ScatterSeriesModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";
ModuleRegistry.registerModules([
AnimationModule,
BubbleSeriesModule,
CategoryAxisModule,
CrosshairModule,
LegendModule,
NumberAxisModule,
ScatterSeriesModule,
ZoomModule,
ContextMenuModule,
]);
@Component({
selector: "my-app",
standalone: true,
imports: [AgCharts],
template: `<div class="example-controls">
<div class="controls-row">
<select (change)="setSeries($event.target.value)">
<option value="bubble" selected="">Bubble</option>
<option value="scatter">Scatter</option>
</select>
<select (change)="setShape($event.target.value)">
<option value="circle" selected="">Circle</option>
<option value="cross">Cross</option>
<option value="diamond">Diamond</option>
<option value="heart">Heart</option>
<option value="plus">Plus</option>
<option value="square">Square</option>
<option value="star">Star</option>
<option value="triangle">Triangle</option>
</select>
<button (click)="setData(1e3)">1k</button>
<button (click)="setData(1e4)">10k</button>
<button (click)="setData(1e5)">100k</button>
<button (click)="setData(1e6)">1m</button>
<label>
<span>Max Visible Items</span>
<input type="range" min="500" max="10000" step="500" value="2000" (change)="setMaxVisibleItems($event.target.valueAsNumber)">
</label>
</div>
</div>
<ag-charts
[options]="options"
></ag-charts>
`,
})
export class AppComponent {
public options;
constructor() {
this.options = {
data: getData(1e4),
animation: { enabled: false },
zoom: {
enabled: true,
axes: "xy",
anchorPointX: "pointer",
anchorPointY: "pointer",
autoScaling: {
enabled: false,
},
},
series: [
{
type: "bubble",
xKey: "x",
yKey: "y",
sizeKey: "size",
maxRenderedItems: 2000,
},
],
theme: {
overrides: {
bubble: {
series: {
fillOpacity: 0.2,
strokeOpacity: 0.2,
},
},
scatter: {
series: {
fillOpacity: 0.2,
strokeOpacity: 0.2,
},
},
},
},
};
}
setSeries = (type: string) => {
const options = clone(this.options);
const { maxRenderedItems, shape } = options.series?.[0] as any;
let series: AgCartesianSeriesOptions;
switch (type) {
case "bubble":
series = {
type: "bubble",
xKey: "x",
yKey: "y",
sizeKey: "size",
shape,
maxRenderedItems,
};
break;
case "scatter":
series = {
type: "scatter",
xKey: "x",
yKey: "y",
shape,
maxRenderedItems,
};
break;
default:
return;
}
options.series = [series];
this.options = options;
};
setShape = (shape: string) => {
const options = clone(this.options);
let series = options.series?.[0] as any;
series.shape = shape;
options.series = [series];
this.options = options;
};
setMaxVisibleItems = (maxRenderedItems: number) => {
const options = clone(this.options);
let series = options.series?.[0] as any;
series.maxRenderedItems = maxRenderedItems;
options.series = [series];
this.options = options;
};
setData = (points: number) => {
const options = clone(this.options);
options.data = getData(points);
this.options = options;
};
}
function sfc32(a: number, b: number, c: number, d: number) {
return function () {
a >>>= 0;
b >>>= 0;
c >>>= 0;
d >>>= 0;
let t = (a + b) | 0;
a = b ^ (b >>> 9);
b = (c + (c << 3)) | 0;
c = (c << 21) | (c >>> 11);
d = (d + 1) | 0;
t = (t + d) | 0;
c = (c + t) | 0;
return (t >>> 0) / 4294967296;
};
}
function seedRandom(seed = 1337): () => number {
const realSeed = seed ^ 0xdeadbeef; // 32-bit seed with optional XOR value
// Pad seed with Phi, Pi and E.
// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
return sfc32(0x9e3779b9, 0x243f6a88, 0xb7e15162, realSeed);
}
export function getData(days: number) {
const random = seedRandom();
return Array.from({ length: days }, () => {
let x = random();
let y = random();
x *= random();
y *= random();
const size = random();
return { x, y, size };
});
}
// Angular entry point file
import '@angular/compiler';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
bootstrapApplication(AppComponent);