or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

chart-directive.mdconfiguration.mdindex.mdtheming.md

theming.mddocs/

0

# Dynamic Theming

1

2

The ThemeService provides dynamic theming capabilities for ng2-charts, allowing applications to change chart colors and styling at runtime based on user preferences or application state.

3

4

## Capabilities

5

6

### ThemeService

7

8

Injectable service that manages dynamic theme options for all charts in the application.

9

10

```typescript { .api }

11

/**

12

* Service for managing dynamic chart themes

13

* Allows runtime updates to chart styling and colors

14

*/

15

@Injectable({

16

providedIn: 'root'

17

})

18

export class ThemeService {

19

/**

20

* Observable stream of current theme options

21

* Charts automatically update when this changes

22

*/

23

colorschemesOptions: BehaviorSubject<ChartOptions | undefined>;

24

}

25

```

26

27

### Theme Configuration

28

29

Set theme options that will be applied to all charts.

30

31

```typescript { .api }

32

/**

33

* Sets global theme options for all charts

34

* Options are merged with individual chart options

35

* @param options - Chart.js options object with theme overrides

36

*/

37

setColorschemesOptions(options: ChartConfiguration['options']): void;

38

39

/**

40

* Gets the current theme options

41

* @returns Current theme configuration or undefined

42

*/

43

getColorschemesOptions(): ChartConfiguration['options'];

44

```

45

46

**Usage Examples:**

47

48

```typescript

49

import { Component, OnInit } from '@angular/core';

50

import { BaseChartDirective, ThemeService } from 'ng2-charts';

51

import { ChartOptions, ChartData } from 'chart.js';

52

53

@Component({

54

selector: 'app-theme-demo',

55

template: `

56

<div class="theme-controls">

57

<button (click)="setLightTheme()">Light Theme</button>

58

<button (click)="setDarkTheme()">Dark Theme</button>

59

<button (click)="setCustomTheme()">Custom Theme</button>

60

</div>

61

62

<canvas baseChart [data]="chartData" [type]="'bar'"></canvas>

63

`,

64

standalone: true,

65

imports: [BaseChartDirective]

66

})

67

export class ThemeDemoComponent implements OnInit {

68

69

constructor(private themeService: ThemeService) {}

70

71

chartData: ChartData = {

72

labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],

73

datasets: [{

74

label: 'Sample Data',

75

data: [12, 19, 3, 5, 2, 3]

76

}]

77

};

78

79

setLightTheme() {

80

const lightTheme: ChartOptions = {

81

plugins: {

82

legend: {

83

labels: {

84

color: '#333333'

85

}

86

}

87

},

88

scales: {

89

x: {

90

ticks: {

91

color: '#333333'

92

},

93

grid: {

94

color: 'rgba(0, 0, 0, 0.1)'

95

}

96

},

97

y: {

98

ticks: {

99

color: '#333333'

100

},

101

grid: {

102

color: 'rgba(0, 0, 0, 0.1)'

103

}

104

}

105

}

106

};

107

108

this.themeService.setColorschemesOptions(lightTheme);

109

}

110

111

setDarkTheme() {

112

const darkTheme: ChartOptions = {

113

plugins: {

114

legend: {

115

labels: {

116

color: '#ffffff'

117

}

118

}

119

},

120

scales: {

121

x: {

122

ticks: {

123

color: '#ffffff'

124

},

125

grid: {

126

color: 'rgba(255, 255, 255, 0.1)'

127

}

128

},

129

y: {

130

ticks: {

131

color: '#ffffff'

132

},

133

grid: {

134

color: 'rgba(255, 255, 255, 0.1)'

135

}

136

}

137

}

138

};

139

140

this.themeService.setColorschemesOptions(darkTheme);

141

}

142

143

setCustomTheme() {

144

const customTheme: ChartOptions = {

145

plugins: {

146

legend: {

147

labels: {

148

color: '#ff6b6b',

149

font: {

150

size: 14,

151

weight: 'bold'

152

}

153

}

154

}

155

},

156

scales: {

157

x: {

158

ticks: {

159

color: '#4ecdc4'

160

},

161

grid: {

162

color: 'rgba(78, 205, 196, 0.3)'

163

}

164

},

165

y: {

166

ticks: {

167

color: '#4ecdc4'

168

},

169

grid: {

170

color: 'rgba(78, 205, 196, 0.3)'

171

}

172

}

173

}

174

};

175

176

this.themeService.setColorschemesOptions(customTheme);

177

}

178

}

179

```

180

181

## Theme Override Behavior

182

183

The ThemeService uses a special merging behavior for theme options:

184

185

- **Simple fields**: Direct replacement of matching fields in chart options

186

- **Arrays**: Single object in theme array acts as template for all elements in chart array

187

- **Objects**: Deep merge with existing chart options

188

189

### Array Override Example

190

191

```typescript

192

// Theme setting that affects ALL axes

193

const themeOptions: ChartOptions = {

194

scales: {

195

x: [{ // Single object template

196

ticks: { color: 'white' },

197

gridLines: { color: 'rgba(255,255,255,0.1)' }

198

}],

199

y: [{ // Single object template

200

ticks: { color: 'white' },

201

gridLines: { color: 'rgba(255,255,255,0.1)' }

202

}]

203

}

204

};

205

206

// This will apply the styling to ALL x and y axes in ALL charts

207

themeService.setColorschemesOptions(themeOptions);

208

```

209

210

## Advanced Theming Patterns

211

212

### Reactive Theme Switching

213

214

```typescript

215

import { Component } from '@angular/core';

216

import { BaseChartDirective, ThemeService } from 'ng2-charts';

217

import { ChartOptions } from 'chart.js';

218

import { BehaviorSubject } from 'rxjs';

219

220

type Theme = 'light' | 'dark' | 'blue';

221

222

@Component({

223

selector: 'app-reactive-theme',

224

template: `

225

<select (change)="onThemeChange($event)">

226

<option value="light">Light</option>

227

<option value="dark">Dark</option>

228

<option value="blue">Blue</option>

229

</select>

230

`,

231

standalone: true,

232

imports: [BaseChartDirective]

233

})

234

export class ReactiveThemeComponent {

235

private themeSubject = new BehaviorSubject<Theme>('light');

236

237

constructor(private themeService: ThemeService) {

238

this.themeSubject.subscribe(theme => {

239

this.applyTheme(theme);

240

});

241

}

242

243

onThemeChange(event: any) {

244

this.themeSubject.next(event.target.value as Theme);

245

}

246

247

private applyTheme(theme: Theme) {

248

const themes = {

249

light: {

250

plugins: {

251

legend: { labels: { color: '#333' } }

252

},

253

scales: {

254

x: { ticks: { color: '#333' } },

255

y: { ticks: { color: '#333' } }

256

}

257

},

258

dark: {

259

plugins: {

260

legend: { labels: { color: '#fff' } }

261

},

262

scales: {

263

x: { ticks: { color: '#fff' } },

264

y: { ticks: { color: '#fff' } }

265

}

266

},

267

blue: {

268

plugins: {

269

legend: { labels: { color: '#2196f3' } }

270

},

271

scales: {

272

x: { ticks: { color: '#2196f3' } },

273

y: { ticks: { color: '#2196f3' } }

274

}

275

}

276

};

277

278

this.themeService.setColorschemesOptions(themes[theme]);

279

}

280

}

281

```

282

283

### Theme Persistence

284

285

```typescript

286

import { Injectable } from '@angular/core';

287

import { ThemeService } from 'ng2-charts';

288

import { ChartOptions } from 'chart.js';

289

290

@Injectable({

291

providedIn: 'root'

292

})

293

export class PersistentThemeService {

294

private readonly THEME_KEY = 'chart-theme';

295

296

constructor(private themeService: ThemeService) {

297

this.loadSavedTheme();

298

}

299

300

setTheme(options: ChartOptions) {

301

this.themeService.setColorschemesOptions(options);

302

localStorage.setItem(this.THEME_KEY, JSON.stringify(options));

303

}

304

305

private loadSavedTheme() {

306

const saved = localStorage.getItem(this.THEME_KEY);

307

if (saved) {

308

try {

309

const theme = JSON.parse(saved);

310

this.themeService.setColorschemesOptions(theme);

311

} catch (e) {

312

console.warn('Failed to load saved theme:', e);

313

}

314

}

315

}

316

}

317

```

318

319

### CSS Variable Integration

320

321

```typescript

322

import { Component, OnInit } from '@angular/core';

323

import { BaseChartDirective, ThemeService } from 'ng2-charts';

324

import { ChartOptions, ChartData } from 'chart.js';

325

326

@Component({

327

selector: 'app-css-theme',

328

template: `<canvas baseChart [data]="chartData" [type]="'line'"></canvas>`,

329

styles: [`

330

:host {

331

--primary-color: #2196f3;

332

--text-color: #333333;

333

--grid-color: rgba(0, 0, 0, 0.1);

334

}

335

336

:host.dark-theme {

337

--primary-color: #90caf9;

338

--text-color: #ffffff;

339

--grid-color: rgba(255, 255, 255, 0.1);

340

}

341

`],

342

standalone: true,

343

imports: [BaseChartDirective]

344

})

345

export class CssThemeComponent implements OnInit {

346

347

chartData: ChartData = {

348

labels: ['January', 'February', 'March', 'April', 'May', 'June'],

349

datasets: [{

350

label: 'Sample Data',

351

data: [12, 19, 3, 5, 2, 3]

352

}]

353

};

354

355

constructor(private themeService: ThemeService) {}

356

357

ngOnInit() {

358

this.updateThemeFromCSS();

359

}

360

361

private updateThemeFromCSS() {

362

const computedStyle = getComputedStyle(document.documentElement);

363

const primaryColor = computedStyle.getPropertyValue('--primary-color').trim();

364

const textColor = computedStyle.getPropertyValue('--text-color').trim();

365

const gridColor = computedStyle.getPropertyValue('--grid-color').trim();

366

367

const theme: ChartOptions = {

368

plugins: {

369

legend: {

370

labels: {

371

color: textColor

372

}

373

}

374

},

375

scales: {

376

x: {

377

ticks: { color: textColor },

378

grid: { color: gridColor }

379

},

380

y: {

381

ticks: { color: textColor },

382

grid: { color: gridColor }

383

}

384

}

385

};

386

387

this.themeService.setColorschemesOptions(theme);

388

}

389

}

390

```

391

392

## Theme Option Types

393

394

```typescript { .api }

395

interface ThemeOptions extends ChartOptions {

396

plugins?: {

397

legend?: {

398

labels?: {

399

color?: string;

400

font?: {

401

size?: number;

402

weight?: string | number;

403

family?: string;

404

};

405

};

406

};

407

tooltip?: {

408

backgroundColor?: string;

409

titleColor?: string;

410

bodyColor?: string;

411

borderColor?: string;

412

};

413

};

414

scales?: {

415

[key: string]: {

416

ticks?: {

417

color?: string;

418

font?: {

419

size?: number;

420

family?: string;

421

};

422

};

423

grid?: {

424

color?: string;

425

borderColor?: string;

426

};

427

};

428

};

429

}

430

```