ngx-lightweight-charts
v0.3.6
Published
Angular wrapper for Trading View lightweight-charts
Downloads
299
Maintainers
Readme
ngx-lightweight-charts
An easily extendable Angular wrapper for Trading View lightweight-charts
What it is.
A wrapper that exposes core chart functionality within an Angular app, and allows new functionality to be easily added.
What it's not.
A (re)implementation of the entire lightweight-charts
api.
How to use.
- Getting started
- Displaying a chart
- Common chart inputs and outputs
- TVChart - accessing the underlying IChartAPI and ISeriesApi instance
- Displaying custom data
- Implemented behaviour
- Adding behaviour
1.
Getting started
| Version | Angular version |
|:--------|---------------|
| 0.3.x
| 18 |
| 0.2.x
| 17 |
Installation
npm i ngx-lightweight-charts
Add providers
import { ApplicationConfig } from '@angular/core';
import { getTVChartDefaultProviders } from "ngx-lightweight-charts";
export const appConfig: ApplicationConfig = {
providers: [
// ...
getTVChartDefaultProviders()
]
};
2.
Displaying a chart
There are two ways:
Either use the tvChart
directive, specifying the type of chart to be displayed.
<div tvChart="Line" [data]="lineData"></div>
Or use one of the following convenience components that wrap tvChart
to create a specific chart type.
<tv-area-chart [data]="pointData"></tv-area-chart>
<tv-bar-chart [data]="barData"></tv-bar-chart>
<tv-baseline-chart [data]="pointData"></tv-baseline-chart>
<tv-candlestick-chart [data]="klineData"></tv-candlestick-chart>
<tv-histogram-chart [data]="pointData"></tv-histogram-chart>
<tv-line-chart [data]="pointData"></tv-line-chart>
3.
Common chart inputs and outputs
All charts expose the following signal based inputs and outputs:
(Generic type T
extends SeriesType and HorzItemScale
defaults to Time)
| Input | type | |:---------------------------|:------------------------------------------------| | id | string | | options | DeepPartial<ChartOptions> | | seriesOptions | SeriesPartialOptionsMap[T] | | data | SeriesDataItemTypeMap<HorzScaleItem>[T][] | | markers | SeriesMarker<HorzScaleItem>[] |
| Output | type | |:---------------------------|:--------------------------------------| | initialised | TVChart<T, HorzScaleItem> | | chartClick | MouseEventParams<HorzScaleItem> | | chartDBLClick | MouseEventParams<HorzScaleItem> | | crosshairMoved | MouseEventParams<HorzScaleItem> | | visibleTimeRangeChanged | Range<HorzScaleItem> | | visibleLogicalRangeChanged | LogicalRange | null | | sizeChanged | number | | dataChanged | DataChangedScope |
4.
TVChart - accessing the underlying IChartAPI and ISeriesApi instance
TVChart
is the core class that creates, manages and exposes a trading view chart and its associated series.
For convenience TVChart
implements the majority of the IChartApi
interface and also exposes the IChartApi
, ITimeScaleApi
and ISeriesApi
subscriptions as RXJS streams.
It also exposes the underlying chart, timeScale, priceScale and series through accessors.
Every chart directive/component is simply a container that initialises an injected TVChart
instance and exposes
a limited set of inputs and outputs to interact with the core functionality of the chart and series.
Once a TVChart
has been initialised, there are 2 ways to access it:
1). Through the initialised
output of the chart directive/component
import {Component} from "@angular/core";
import {TVChartDirective, TVChart} from "ngx-lightweight-chart";
import {LineData} from "lightweight-charts";
@Component({
selector: 'my-component',
standalone: true,
imports: [
TVChartDirective
],
template: `
<div tvChart="Line" [data]="chartData" (initialised)="onChartInit($event)"></div>
`
})
export class MyComponent {
chartData: LineData[]
onChartInit(chart: TVChart<"Line">) {
//... perform some action through the TVChart API
}
}
2). Through the tvChartCollector
directive when creating reusable functionality, which can be used to access and interact with a single TVChart
or a collection.
The tvChartCollector
also ensures that all TVChart
instances have been fully initialised before exposing them for access through the charts
signal.
Accessing a single TVChart
instance:
<div tvChart="Line" [data]="chartData" tvChartCollector myDirective></div>
import {Directive, effect, inject} from "@angular/core";
import {TVChartCollectorDirective, TVChart} from "ngx-lightweight-charts";
@Directive({
selector: '[myDirective]',
standalone: true
})
export class MyDirective {
readonly #collector = inject(TVChartCollectorDirective);
constructor() {
effect(() => {
this.#collector.charts()?.forEach((chart: TVChart<any>) => {
//... perform some action through the TVChart API
});
});
}
}
Accessing multiple TVChart instances:
<div tvChartCollector myMultiChartDirective>
<tv-candlestick-chart [data]="klineData"></tv-candlestick-chart>
<tv-histogram-chart [data]="pointData"></tv-histogram-chart>
<tv-line-chart [data]="pointData"></tv-line-chart>
</div>
import {Directive, effect, inject} from "@angular/core";
import {TVChartCollectorDirective, TVChart} from "ngx-lightweight-charts";
@Directive({
selector: '[myMultiChartDirective]',
standalone: true
})
export class MyMultiChartDirective {
readonly #collector = inject(TVChartCollectorDirective);
constructor() {
effect(() => {
this.#collector.charts()?.forEach((chart: TVChart<any>) => {
//... perform some action through the TVChart API
});
});
}
}
You may have noticed that the implementation of MyDirective
and MyMultiChartDirective
are identical. This is intentional.
The TVChartCollectorDirective.charts
signal always returns an array of charts (whether collecting a single or multiple)
allowing the flexibility to easily implement directives or components that work with single and/or multiple charts.
The tvChartCollector
also accepts an array of id's to facilitate the filtering of charts by id:
<div [tvChartCollector]="['one, 'two']" myDirective>
<tv-candlestick-chart id="one" [data]="klineData"></tv-candlestick-chart>
<tv-histogram-chart id="two" [data]="pointData"></tv-histogram-chart>
<tv-line-chart [data]="pointData"></tv-line-chart>
</div>
import {Directive, effect, inject} from "@angular/core";
import {TVChartCollectorDirective, TVChart} from "ngx-lightweight-charts";
@Directive({
selector: '[myDirective]',
standalone: true
})
export class MyDirective {
readonly #collector = inject(TVChartCollectorDirective);
constructor() {
effect(() => {
this.#collector.charts()?.forEach((chart: TVChart<any>) => {
//... perform something only on chart "one" and "two"
});
});
}
}
5.
Displaying custom data
The following example uses the Custom chart HLC area implementation - source code can be found here
Given the following app component:
import {Component} from "@angular/core";
@Component({
selector: 'app-root',
standalone: true,
templateUrl: './app.component.html'
})
export class AppComponent {
customSeriesView = new HLCAreaSeries();
customData = generateAlternativeCandleData(100);
}
There are 2 ways to display custom data:
1). Using the TVChartCustomSeriesComponent
<tv-custom-series-chart [data]="customData" [customSeriesView]="customSeriesView"></tv-custom-series-chart>
2). By adding an additional (custom) series to an existing chart
<div tvChart="Candlestick" [data]="customData" tvChartCollector [customSeriesExample]="customSeriesView"></div>
import {Directive, effect, inject, input} from "@angular/core";
import {TVChartCollectorDirective, TVChart} from "ngx-lightweight-charts";
import {CustomData, CustomSeriesOptions, ICustomSeriesPaneView, ISeriesApi, Time} from "lightweight-charts";
@Directive({
selector: '[customSeriesExample]',
standalone: true
})
export class CustomSeriesExampleDirective<HorzScaleItem = Time> {
readonly #collector = inject(TVChartCollectorDirective);
data = input<CustomData<HorzScaleItem>[]>();
customSeriesView = input.required<ICustomSeriesPaneView<HorzScaleItem>>({alias: 'customSeriesExample'});
seriesOptions = input<CustomSeriesOptions>({} as CustomSeriesOptions);
#series?: ISeriesApi<'Custom', HorzScaleItem>;
constructor() {
effect(() => {
this.#collector.charts()?.forEach((chart: TVChart<'Candlestick', HorzScaleItem>) => {
const data = this.data(),
customSeriesView= this.customSeriesView();
if(!data || !customSeriesView) {
return;
}
({
series: this.#series
} = chart.addAdditionalSeries('Custom', this.seriesOptions(), customSeriesView));
this.#series?.setData(data);
});
});
}
}
6.
Implemented behaviour
TVChartGroupDirective
Visually groups multiple charts
<div tvChartCollector tvChartGroup>
<tv-area-chart [data]="pointData"></tv-area-chart>
<tv-histogram-chart [data]="pointData"></tv-histogram-chart>
<tv-line-chart [data]="pointData"></tv-line-chart>
</div>
TVChartSyncDirective
Syncs the visible logical range (scale and position) and cross-hair of multiple charts
<div tvChartCollector tvChartSync>
<tv-candlestick-chart [data]="klineData"></tv-candlestick-chart>
<tv-histogram-chart [data]="pointData"></tv-histogram-chart>
</div>
TVChartCrosshairDataDirective
Outputs data relating to the current cross-hair position
Single chart:
<tv-candlestick-chart [data]="klineData" tvChartCollector (tvChartCrosshairData)="onCrosshairData($event)"></tv-candlestick-chart>
import {Component} from "@angular/core";
import {TVChartCrosshairDataDirective} from "ngx-lightweight-charts";
@Component({
selector: 'app-root',
standalone: true,
imports: [
TVChartCrosshairDataDirective
],
templateUrl: './app.component.html'
})
export class AppComponent {
onCrosshairData(data: {[key: string | number]: Record<string, any>}): void {
/*
The format of the data is as follows
{
[chart id || index]: {
// cross-hair point data
}
}
*/
// do something with data here...
}
}
Multiple charts:
<div tvChartCollector tvChartSync (tvChartCrosshairData)="onCrosshairData($event)">
<tv-candlestick-chart id="ohlc" [data]="klines" [options]="{rightPriceScale: {minimumWidth: 80}}"></tv-candlestick-chart>
<div tvChart="Histogram" [data]="rsiValues" [options]="{rightPriceScale: {minimumWidth: 80}}"></div>
</div>
import {Component} from "@angular/core";
import {OhlcData, HistogramData, Time} from "lightweight-charts";
import {TVChartCrosshairDataDirective} from "ngx-lightweight-charts";
@Component({
selector: 'app-root',
standalone: true,
imports: [
TVChartCrosshairDataDirective
],
templateUrl: './app.component.html'
})
export class AppComponent {
klines: OhlcData<Time>[] = [/* loaded kline data */];
rsiData: HistogramData<Time>[] = [/* loaded rsi data */];
onCrosshairData(data: {[key: string | number]: Record<string, any>}): void {
/*
The format of the data is as follows
{
ohlc: {
time: ...,
open: ...,
high: ...,
low: ...,
close: ...
},
2: {
time: ...,
value: ...
}
}
*/
// do something with data here...
}
}
7.
Adding behaviour
To add your own behaviour it's as simple as doing the following:
<div tvChart="Line" [data]="chartData" tvChartCollector yourDirective></div>
import {Directive, effect, inject} from "@angular/core";
import {TVChartCollectorDirective, TVChart} from "ngx-lightweight-charts";
@Directive({
selector: '[yourDirective]',
standalone: true
})
export class YourDirective {
readonly #collector = inject(TVChartCollectorDirective);
constructor() {
effect(() => {
this.#collector.charts()?.forEach((chart: TVChart<any>) => {
//... perform some action through the TVChart API
});
});
}
}