Skip to content
silverpoint
Documentation menu

Getting started · Frameworks

Angular

Everything you need to use silverpoint with Angular: install, quickstart, app-wide configuration, precision mode, interaction, export, server rendering, the UI components and what 0.7 adds.

Install

Package@silverpoint/angular
Peers@angular/core, @angular/common and @angular/forms >=21 <23; @knight-lab/timelinejs ^3.9.13 (optional)
IntegrationThe Angular CLI (@angular/build, on Vite) is validated, including @angular/ssr.
ComponentsSpLineChart · <sp-line-chart>
Import from@silverpoint/angular/<chart>
App-wide configurationprovideSilverpoint (provider)
shell
npm install @silverpoint/angular @silverpoint/grounds @silverpoint/fonts

Quickstart

Create a fresh app and install silverpoint:

shell
npx @angular/cli@22 new my-charts --defaults --skip-git
cd my-charts
npm install @silverpoint/angular @silverpoint/grounds @silverpoint/fonts
npm start

Then replace the app's entry with:

ts
/* 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 },
  ];
}
Hits per hourHits per hour
Hits per hour
hourhits
0018
0411
0842
1264
1657
2030

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.

ts
// 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="%" />
Units soldUnits sold
Units sold
monthunits
Jan120
Feb98
Mar143
Sales by channelSales by channel
Sales by channel
channelshareshare
Web5454%
Stores3131%
Partners1515%

Precision mode

ts
<sp-line-chart [data]="data" xKey="hour" valueKey="hits" title="Hits per hour" mode="precision" />

Interaction and a custom readout

ts
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

ts
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

shell
# 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.mjs

UI 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:

ts
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()); }
}
Overview: the charts of this view.

Every component has a reference page with each of its states in this framework:

UI components: values, forms, keyboard →

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:

ts
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: