Getting started · Frameworks
Angular
Install
| Package | @silverpoint/angular |
| Peers | @angular/core, @angular/common and @angular/forms >=21 <23; @knight-lab/timelinejs ^3.9.13 (optional) |
| Integration | The Angular CLI (@angular/build, on Vite) is validated, including @angular/ssr. |
| Components | SpLineChart · <sp-line-chart> |
| Import from | @silverpoint/angular/<chart> |
| App-wide configuration | provideSilverpoint (provider) |
npm install @silverpoint/angular @silverpoint/grounds @silverpoint/fontsQuickstart
Create a fresh app and install silverpoint:
npx @angular/cli@22 new my-charts --defaults --skip-git
cd my-charts
npm install @silverpoint/angular @silverpoint/grounds @silverpoint/fonts
npm startThen replace the app's entry with:
/* src/styles.css */
@import '@silverpoint/fonts/fonts.css';
@import '@silverpoint/grounds/styles.css';
// src/app/app.ts
import { Component } from '@angular/core';
import { SpLineChart } from '@silverpoint/angular/line-chart';
@Component({
selector: 'app-root',
imports: [SpLineChart],
template: `
<div style="width: 480px">
<sp-line-chart [data]="data" xKey="hour" valueKey="hits" title="Hits per hour" />
</div>
`,
})
export class App {
protected readonly data = [
{ hour: '00', hits: 18 },
{ hour: '04', hits: 11 },
{ hour: '08', hits: 42 },
{ hour: '12', hits: 64 },
{ hour: '16', hits: 57 },
{ hour: '20', hits: 30 },
];
}| hour | hits |
|---|---|
| 00 | 18 |
| 04 | 11 |
| 08 | 42 |
| 12 | 64 |
| 16 | 57 |
| 20 | 30 |
The chart takes the width of its container. height is the height of the drawing area and defaults to 160 px. Omit data and a chart draws its own demo dataset.
One ground for the whole app
Set the ground, the substrate, the mode and the locale once for every chart. A prop on a chart always wins.
// src/app/app.config.ts
import { type ApplicationConfig, provideZonelessChangeDetection } from '@angular/core';
import { provideSilverpoint } from '@silverpoint/angular';
export const appConfig: ApplicationConfig = {
providers: [
provideZonelessChangeDetection(),
provideSilverpoint({ ground: 'silverpoint', substrate: 'green', locale: 'en-GB' }),
],
};
<!-- any template -->
<sp-bar-chart [data]="sales" xKey="month" valueKey="units" title="Units sold" unit="units" />
<sp-donut-chart [data]="channels" nameKey="channel" valueKey="share" title="Sales by channel" centerLabel="%" />| month | units |
|---|---|
| Jan | 120 |
| Feb | 98 |
| Mar | 143 |
| channel | share | share |
|---|---|---|
| Web | 54 | 54% |
| Stores | 31 | 31% |
| Partners | 15 | 15% |
Precision mode
<sp-line-chart [data]="data" xKey="hour" valueKey="hits" title="Hits per hour" mode="precision" />Interaction and a custom readout
import { Component, input, signal } from '@angular/core';
import { SpTooltip } from '@silverpoint/angular';
import { SpLineChart } from '@silverpoint/angular/line-chart';
type Row = { hour: string; hits: number };
@Component({
selector: 'app-explorer',
imports: [SpLineChart, SpTooltip],
template: `
<sp-line-chart
[data]="data()"
xKey="hour"
valueKey="hits"
title="Hits per hour"
(activeChange)="active.set($event ? $event.datum['hour'] + ': ' + $event.value : '—')"
(select)="selected($event.datum)"
>
<ng-template spTooltip let-item>
<strong>{{ item.value }} hits</strong>
</ng-template>
</sp-line-chart>
<p>Under the pointer: {{ active() }}</p>
`,
})
export class Explorer {
readonly data = input.required<Row[]>();
protected readonly active = signal('—');
protected selected(datum: unknown) {
console.log('selected', datum);
}
}Export: the imperative handle
import { Component, viewChild } from '@angular/core';
import { SpLineChart } from '@silverpoint/angular/line-chart';
@Component({
selector: 'app-exportable',
imports: [SpLineChart],
template: `
<sp-line-chart #chart [data]="data" xKey="hour" valueKey="hits" title="Hits per hour" />
<button (click)="download()">Export SVG</button>
`,
})
export class Exportable {
protected readonly data = [
{ hour: '00', hits: 18 },
{ hour: '12', hits: 64 },
];
private readonly chart = viewChild.required<SpLineChart>('chart');
protected download() {
const svg = this.chart().toSVGString();
window.open(URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' })));
}
}Server rendering
# Angular CLI with @angular/ssr: nothing silverpoint-specific to configure.
ng add @angular/ssr
# angular.json: "outputMode": "server"
npm run build && node dist/my-charts/server/server.mjsUI components
Since 0.3: 17 interface components from @silverpoint/angular/ui, drawn as the charts are. Import @silverpoint/grounds/ui.css once, beside styles.css. A form with a controlled input, a switch, tabs and a submit button:
import { Component, computed, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { SpButton, SpInput, SpSwitch, SpTabPanel, SpTabs } from '@silverpoint/angular/ui';
import { SpBarChart } from '@silverpoint/angular/bar-chart';
import { SpLineChart } from '@silverpoint/angular/line-chart';
@Component({
selector: 'app-settings',
imports: [FormsModule, SpButton, SpInput, SpSwitch, SpTabs, SpTabPanel, SpBarChart, SpLineChart],
template: `
<form (ngSubmit)="save()">
<!-- [(value)] two-way binds a signal; ngModel and formControl work too (ControlValueAccessor) -->
<sp-input label="City" name="city" [(value)]="city"
[invalid]="city() === ''" message="Required: pick a city" />
<sp-switch label="Precision" name="precision" [(value)]="precision" />
<sp-tabs label="Views" [items]="tabs" [(value)]="view">
<sp-tab-panel value="traffic"><sp-line-chart title="Traffic" [mode]="mode()" /></sp-tab-panel>
<sp-tab-panel value="errors"><sp-bar-chart title="Errors" [mode]="mode()" /></sp-tab-panel>
</sp-tabs>
<button spButton type="submit" variant="primary">Save</button>
</form>
`,
})
export class Settings {
protected readonly city = signal('Caracas');
protected readonly precision = signal(false);
protected readonly view = signal('traffic');
protected readonly mode = computed(() => (this.precision() ? 'precision' : 'ink'));
protected readonly tabs = [{ key: 'traffic', label: 'Traffic' }, { key: 'errors', label: 'Errors' }];
save() { console.log(this.city(), this.precision()); }
}Every component has a reference page with each of its states in this framework:
New in 0.8.0: palettes, overlays, timeline
21 more UI components from the same @silverpoint/angular/ui subpaths — composed ones (table, pagination, statistic, collapse…) and overlays on the platform's <dialog> and Popover API (modal, drawer, popover, tooltip, select, menu, toast) —, a palette on every chart, component and provider, and SpTimeline on @silverpoint/angular/timeline. An overlay opens from a trigger you write:
import { Component, signal } from '@angular/core';
import { SpCardFooter, SpTrigger } from '@silverpoint/angular/ui';
import { SpButton } from '@silverpoint/angular/ui/button';
import { SpModal } from '@silverpoint/angular/ui/modal';
@Component({
selector: 'app-apply-changes',
imports: [SpButton, SpCardFooter, SpModal, SpTrigger],
template: `
<sp-modal [(open)]="open" title="Apply changes" description="The geometry of the data does not move.">
<button type="button" spTrigger>Open the modal</button>
<p>Apply the new ground to every chart on the page?</p>
<ng-template spFooter>
<button spButton variant="primary" (click)="open.set(false)">Apply</button>
</ng-template>
</sp-modal>
`,
})
export class ApplyChanges {
protected readonly open = signal(false);
}The 60 charts
Every chart has a reference page with its example in this framework: