diff --git a/README.md b/README.md
index f258731..903de63 100644
--- a/README.md
+++ b/README.md
@@ -331,6 +331,7 @@ import { HighchartsChartDirective } from 'highcharts-angular';
import('highcharts/esm/modules/exporting'),
];
},
+ timeout: 900, // Optional: increase timeout for loading modules
}),
],
})
@@ -412,6 +413,12 @@ export class StockComponent {
}
```
+**Note:**
+
+- Some Highcharts modules have dependencies and must be loaded in a specific order.
+- In such cases, use a promise chain (e.g., `import('highcharts/esm/highcharts-more').then(() => import('highcharts/esm/modules/dumbbell'))`)
+- instead of just listing them as array items. This ensures the dependent module loads only after its dependency.
+
### To load a wrapper
A wrapper is a [custom extension](https://www.highcharts.com/docs/extending-highcharts/extending-highcharts) for Highcharts. To load a wrapper in the same way as a module, save it as a JavaScript file and add the following code to the beginning and end of the file:
diff --git a/highcharts-angular/src/lib/highcharts-chart.component.spec.ts b/highcharts-angular/src/lib/highcharts-chart.component.spec.ts
new file mode 100644
index 0000000..2893315
--- /dev/null
+++ b/highcharts-angular/src/lib/highcharts-chart.component.spec.ts
@@ -0,0 +1,167 @@
+import { Component, ChangeDetectionStrategy } from '@angular/core';
+import { TestBed } from '@angular/core/testing';
+import type Highcharts from 'highcharts/esm/highcharts';
+import { HighchartsChartComponent } from './highcharts-chart.component';
+import { HighchartsChartService } from './highcharts-chart.service';
+import { provideHighcharts, providePartialHighcharts } from './highcharts-chart.provider';
+import { ModuleFactoryFunction } from './types';
+
+/**
+ * Minimal host component to attach per-test module providers via TestBed.overrideComponent.
+ * We keep it simple to focus on DI and async loading behavior.
+ */
+@Component({
+ selector: 'highcharts-test',
+ template: ``,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ imports: [HighchartsChartComponent],
+ standalone: true,
+})
+class TestComponent {}
+
+describe('TestComponent / HighchartsChartService (load module)', () => {
+ beforeEach(async () => {
+ // 1) Register the standalone host + core Highcharts provider.
+ // - provideHighcharts(): should wire up HIGHCHARTS_LOADER, etc., so the service can load core Highcharts.
+ await TestBed.configureTestingModule({
+ imports: [TestComponent],
+ providers: [provideHighcharts()],
+ }).compileComponents();
+ });
+
+ it('resolves HighchartsChartService from the component injector', () => {
+ const fixture = TestBed.createComponent(TestComponent);
+ fixture.detectChanges();
+
+ // 2) Resolve the service from the component’s injector to honor component-level provider overrides.
+ const service = fixture.debugElement.injector.get(HighchartsChartService);
+ expect(service).toBeTruthy();
+ });
+
+ // ---------------------------------------------------------------------------
+ // Parameterized checks for different Highcharts modules.
+ //
+ // For each case, we:
+ // - override the component’s providers to supply the module list
+ // - create the fixture (activates providers)
+ // - wait for the microtasks/imports to settle (fixture.whenStable)
+ // - assert that the Highcharts instance contains the expected augmented APIs
+ // ---------------------------------------------------------------------------
+
+ type Case = {
+ title: string;
+ modules: ModuleFactoryFunction;
+ assert(hc: any): void;
+ timeout?: number;
+ };
+
+ const CASES: Case[] = [
+ {
+ title: 'map → exposes Highcharts.MapChart',
+ modules: () => [import('highcharts/esm/modules/map')],
+ assert: (hc: typeof Highcharts) => {
+ expect(hc.MapChart).toBeDefined();
+ expect(typeof hc.MapChart).toBe('function');
+ },
+ },
+ {
+ title: 'tilemap → exposes Highcharts.seriesTypes.tilemap',
+ modules: () => [import('highcharts/esm/modules/tilemap')],
+ assert: hc => {
+ expect(hc.seriesTypes?.tilemap).toBeDefined();
+ },
+ },
+ {
+ title: 'highcharts-more → exposes arearange series + dumbbell → exposes Highcharts.seriesTypes.dumbbell',
+ modules: () => [import('highcharts/esm/highcharts-more').then(() => import('highcharts/esm/modules/dumbbell'))],
+ assert: hc => {
+ expect(hc.seriesTypes?.arearange).toBeDefined();
+ expect(hc.seriesTypes?.dumbbell).toBeDefined();
+ },
+ timeout: 2000,
+ },
+ {
+ title: 'pattern-fill → adds SVGRenderer.addPattern',
+ modules: () => [import('highcharts/esm/modules/pattern-fill')],
+ assert: hc => {
+ // pattern-fill augments the renderer with addPattern utility
+ expect(typeof hc.SVGRenderer?.prototype?.addPattern).toBe('function');
+ },
+ },
+ {
+ title: 'gantt → exposes Highcharts.ganttChart or Highcharts.GanttChart',
+ modules: () => [import('highcharts/esm/modules/gantt')],
+ assert: hc => {
+ // Some versions expose both; at least one must exist.
+ const ok = typeof hc.ganttChart === 'function' || typeof hc.GanttChart === 'function';
+ expect(ok).toBeTrue();
+ },
+ },
+ ];
+
+ for (const c of CASES) {
+ it(`attaches expected API when module is provided: ${c.title}`, async () => {
+ // 3) Provide the module(s) at the component level. This mirrors your real component’s
+ // `providers: [providePartialHighcharts({ modules: () => [...] })]`.
+ TestBed.overrideComponent(TestComponent, {
+ set: { providers: [providePartialHighcharts({ modules: c.modules, timeout: c.timeout })] },
+ });
+
+ const fixture = TestBed.createComponent(TestComponent);
+ fixture.detectChanges();
+
+ // 4) Get the service from this component’s injector scope
+ const service = fixture.debugElement.injector.get(HighchartsChartService);
+ expect(service).toBeTruthy();
+
+ // 5) Wait for all async work to stabilize:
+ // - dynamic imports for modules
+ // - the service’s microtasks and internal timers (your working test already relies on whenStable)
+ await fixture.whenStable();
+
+ // 6) Read the Highcharts instance from the signal
+ const hc = service.highcharts();
+ expect(hc).toBeTruthy();
+
+ // 7) Case-specific assertions for the module’s side effects
+ c.assert(hc);
+ });
+ }
+
+ it('can load multiple modules together (map + tilemap + more + dumbbell + pattern-fill + gantt)', async () => {
+ TestBed.overrideComponent(TestComponent, {
+ set: {
+ providers: [
+ providePartialHighcharts({
+ modules: () => [
+ import('highcharts/esm/modules/map'),
+ import('highcharts/esm/modules/tilemap'),
+ import('highcharts/esm/modules/gantt'),
+ import('highcharts/esm/highcharts-more').then(() => import('highcharts/esm/modules/dumbbell')),
+ import('highcharts/esm/modules/pattern-fill'),
+ ],
+ }),
+ ],
+ },
+ });
+
+ const fixture = TestBed.createComponent(TestComponent);
+ fixture.detectChanges();
+
+ const service = fixture.debugElement.injector.get(HighchartsChartService);
+ expect(service).toBeTruthy();
+
+ await fixture.whenStable();
+
+ const hc: any = service.highcharts();
+ expect(hc).toBeTruthy();
+
+ // Consolidated assertions (quick smoke for “all together”)
+ expect(typeof hc.MapChart).toBe('function'); // map
+ expect(hc.seriesTypes?.tilemap).toBeDefined(); // tilemap
+ expect(hc.seriesTypes?.arearange).toBeDefined(); // highcharts-more
+ expect(hc.seriesTypes?.dumbbell).toBeDefined(); // dumbbell
+ expect(typeof hc.SVGRenderer?.prototype?.addPattern).toBe('function'); // pattern-fill
+ expect(typeof hc.ganttChart === 'function' || typeof hc.GanttChart === 'function').toBeTrue(); // gantt
+ });
+});
diff --git a/highcharts-angular/src/lib/highcharts-chart.directive.ts b/highcharts-angular/src/lib/highcharts-chart.directive.ts
index a60d4e4..20041aa 100644
--- a/highcharts-angular/src/lib/highcharts-chart.directive.ts
+++ b/highcharts-angular/src/lib/highcharts-chart.directive.ts
@@ -14,7 +14,7 @@ import {
} from '@angular/core';
import { isPlatformServer } from '@angular/common';
import { HighchartsChartService } from './highcharts-chart.service';
-import { HIGHCHARTS_CONFIG } from './highcharts-chart.token';
+import { HIGHCHARTS_CONFIG, HIGHCHARTS_TIMEOUT } from './highcharts-chart.token';
import { ChartConstructorType, ConstructorChart } from './types';
import type Highcharts from 'highcharts/esm/highcharts';
@@ -58,6 +58,10 @@ export class HighchartsChartDirective {
optional: true,
});
+ private readonly timeout = inject(HIGHCHARTS_TIMEOUT, {
+ optional: true,
+ });
+
private readonly highchartsChartService = inject(HighchartsChartService);
private readonly constructorChart = computed(() => {
@@ -68,8 +72,13 @@ export class HighchartsChartDirective {
return undefined;
});
+ private delay(ms: number): Promise {
+ return new Promise(resolve => setTimeout(resolve, ms));
+ }
+
// Create the chart as soon as we can
- private readonly chart = computed(() => {
+ private readonly chart = computed(async () => {
+ await this.delay(this.relativeConfig?.timeout ?? this.timeout ?? 500);
return this.constructorChart()?.(
this.el.nativeElement,
// Use untracked, so we don't re-create new chart everytime options change
@@ -82,14 +91,16 @@ export class HighchartsChartDirective {
});
private keepChartUpToDate(): void {
- effect(() => {
+ effect(async () => {
+ // Wait for the chart to be created
this.update();
- this.chart()?.update(this.options(), true, this.oneToOne());
+ const chart = await this.chart();
+ chart?.update(this.options(), true, this.oneToOne());
});
}
- private destroyChart(): void {
- const chart = this.chart();
+ private async destroyChart(): Promise {
+ const chart = await this.chart();
if (chart) {
// #56
chart.destroy();
diff --git a/highcharts-angular/src/lib/highcharts-chart.provider.ts b/highcharts-angular/src/lib/highcharts-chart.provider.ts
index 78794cf..017e694 100644
--- a/highcharts-angular/src/lib/highcharts-chart.provider.ts
+++ b/highcharts-angular/src/lib/highcharts-chart.provider.ts
@@ -4,6 +4,7 @@ import {
HIGHCHARTS_CONFIG,
HIGHCHARTS_ROOT_MODULES,
HIGHCHARTS_OPTIONS,
+ HIGHCHARTS_TIMEOUT,
} from './highcharts-chart.token';
import { ModuleFactoryFunction, HighchartsConfig, PartialHighchartsConfig, InstanceFactoryFunction } from './types';
import type Highcharts from 'highcharts/esm/highcharts';
@@ -34,9 +35,10 @@ export function providePartialHighcharts(config: PartialHighchartsConfig): Provi
}
export function provideHighcharts(config: HighchartsConfig = {}): EnvironmentProviders {
- const providers: EnvironmentProviders[] = [
+ const providers: (Provider | EnvironmentProviders)[] = [
provideHighchartsInstance(config.instance),
provideHighchartsRootModules(config.modules ?? emptyModuleFactoryFunction),
+ { provide: HIGHCHARTS_TIMEOUT, useValue: config.timeout },
];
if (config.options) {
providers.push(provideHighchartsOptions(config.options));
diff --git a/highcharts-angular/src/lib/highcharts-chart.service.ts b/highcharts-angular/src/lib/highcharts-chart.service.ts
index 3cef6e6..9a9ecf5 100644
--- a/highcharts-angular/src/lib/highcharts-chart.service.ts
+++ b/highcharts-angular/src/lib/highcharts-chart.service.ts
@@ -5,8 +5,7 @@ import type Highcharts from 'highcharts/esm/highcharts';
@Injectable({ providedIn: 'root' })
export class HighchartsChartService {
- private readonly writableHighcharts = signal(null);
- public readonly highcharts = this.writableHighcharts.asReadonly();
+ public readonly highcharts = signal(null);
private readonly loader = inject(HIGHCHARTS_LOADER);
private readonly globalOptions = inject(HIGHCHARTS_OPTIONS, {
@@ -19,7 +18,7 @@ export class HighchartsChartService {
private async loadHighchartsWithModules(partialConfig: PartialHighchartsConfig | null): Promise {
const highcharts = await this.loader(); // Ensure Highcharts core is loaded
- await Promise.all([...(this.globalModules?.() ?? []), ...(partialConfig?.modules?.() ?? [])]);
+ await Promise.allSettled([...(this.globalModules?.() ?? []), ...(partialConfig?.modules?.() ?? [])]);
// Return the Highcharts instance
return highcharts;
@@ -30,8 +29,7 @@ export class HighchartsChartService {
if (this.globalOptions) {
highcharts.setOptions(this.globalOptions);
}
- // add timeout to make sure the loader has attached all modules
- setTimeout(() => this.writableHighcharts.set(highcharts), 100);
+ this.highcharts.set(highcharts);
});
}
}
diff --git a/highcharts-angular/src/lib/highcharts-chart.token.ts b/highcharts-angular/src/lib/highcharts-chart.token.ts
index 1945255..0b0082c 100644
--- a/highcharts-angular/src/lib/highcharts-chart.token.ts
+++ b/highcharts-angular/src/lib/highcharts-chart.token.ts
@@ -6,3 +6,4 @@ export const HIGHCHARTS_LOADER = new InjectionToken('HI
export const HIGHCHARTS_ROOT_MODULES = new InjectionToken('HIGHCHARTS_ROOT_MODULES');
export const HIGHCHARTS_OPTIONS = new InjectionToken('HIGHCHARTS_OPTIONS');
export const HIGHCHARTS_CONFIG = new InjectionToken('HIGHCHARTS_CONFIG');
+export const HIGHCHARTS_TIMEOUT = new InjectionToken('HIGHCHARTS_TIMEOUT');
diff --git a/highcharts-angular/src/lib/types.ts b/highcharts-angular/src/lib/types.ts
index a0041dd..df60bb5 100644
--- a/highcharts-angular/src/lib/types.ts
+++ b/highcharts-angular/src/lib/types.ts
@@ -21,6 +21,11 @@ export type PartialHighchartsConfig = {
* Include Highcharts additional modules (e.g., exporting, accessibility) or custom themes
*/
modules?: ModuleFactoryFunction;
+ /**
+ * Timeout in milliseconds to wait for the Highcharts library to load
+ * Default is 500ms
+ */
+ timeout?: number;
};
export type HighchartsConfig = {
diff --git a/package.json b/package.json
index 5495e83..a46e7a6 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"run:ssr": "node dist/my-ssr-app/server/server.mjs",
"test": "ng test my-app",
"lint": "ng lint",
+ "prettier": "prettier . --write",
"release": "cd ./highcharts-angular && standard-version && cd ../ && node tasks/build.js && node tasks/release.js",
"release-minor": "cd ./highcharts-angular && standard-version --release-as minor && cd ../ && node tasks/build.js && node tasks/release.js",
"release-major": "cd ./highcharts-angular && standard-version --release-as major && cd ../ && node tasks/build.js && node tasks/release.js",
diff --git a/src/app/app.component.html b/src/app/app.component.html
index a22188c..be58e88 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -2,6 +2,8 @@
+
+
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index b97868c..5ede2d4 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -4,12 +4,22 @@ import { StockChartComponent } from './stock-chart/stock-chart.component';
import { MapChartComponent } from './map-chart/map-chart.component';
import { GanttChartComponent } from './gantt-chart/gantt-chart.component';
import { LazyLoadingChartComponent } from './lazy-loading-chart/lazy-loading-chart.component';
+import { TilemapChartComponent } from './tilemap-chart/tilemap-chart.component';
+import { DumbbellChartComponent } from './dumbbell-chart/dumbbell-chart.component';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css',
- imports: [LineChartComponent, StockChartComponent, MapChartComponent, GanttChartComponent, LazyLoadingChartComponent],
+ imports: [
+ LineChartComponent,
+ StockChartComponent,
+ MapChartComponent,
+ GanttChartComponent,
+ LazyLoadingChartComponent,
+ TilemapChartComponent,
+ DumbbellChartComponent,
+ ],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
diff --git a/src/app/dumbbell-chart/dumbbell-chart.component.css b/src/app/dumbbell-chart/dumbbell-chart.component.css
new file mode 100644
index 0000000..6a487ef
--- /dev/null
+++ b/src/app/dumbbell-chart/dumbbell-chart.component.css
@@ -0,0 +1,11 @@
+h2 {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 1.25rem;
+ margin: 0 0 1.5rem 0;
+}
+
+.main {
+ width: 100%;
+ height: 650px;
+ display: block;
+}
diff --git a/src/app/dumbbell-chart/dumbbell-chart.component.html b/src/app/dumbbell-chart/dumbbell-chart.component.html
new file mode 100644
index 0000000..f76f5ae
--- /dev/null
+++ b/src/app/dumbbell-chart/dumbbell-chart.component.html
@@ -0,0 +1,4 @@
+
+ Demo #8: Highcharts Dumbbell
+
+
diff --git a/src/app/dumbbell-chart/dumbbell-chart.component.ts b/src/app/dumbbell-chart/dumbbell-chart.component.ts
new file mode 100644
index 0000000..5bde675
--- /dev/null
+++ b/src/app/dumbbell-chart/dumbbell-chart.component.ts
@@ -0,0 +1,197 @@
+import { Component, ChangeDetectionStrategy } from '@angular/core';
+import { HighchartsChartComponent } from 'highcharts-angular';
+import { providePartialHighcharts } from 'highcharts-angular';
+
+@Component({
+ selector: 'app-dumbbell-chart',
+ imports: [HighchartsChartComponent],
+ templateUrl: './dumbbell-chart.component.html',
+ styleUrl: './dumbbell-chart.component.css',
+ providers: [
+ providePartialHighcharts({
+ modules: () => {
+ return [
+ import('highcharts/esm/highcharts-more'),
+ import('highcharts/esm/modules/dumbbell'),
+ import('highcharts/esm/modules/pattern-fill'),
+ ];
+ },
+ timeout: 900,
+ }),
+ ],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class DumbbellChartComponent {
+ public options: Highcharts.Options = {
+ chart: {
+ plotBorderWidth: 1,
+ zooming: {
+ type: 'y',
+ resetButton: {
+ theme: { style: { display: 'none' } },
+ },
+ },
+ spacingLeft: 1,
+ spacingRight: 1,
+ spacingTop: 7,
+ spacingBottom: 0,
+ animation: false,
+ panning: {
+ enabled: true,
+ type: 'y',
+ },
+ panKey: 'shift',
+ },
+ plotOptions: {
+ columnrange: {
+ grouping: false,
+ },
+ },
+ legend: { enabled: false },
+ credits: { enabled: false },
+ title: { text: '' },
+ yAxis: {
+ reversed: true,
+ title: { text: '' },
+ startOnTick: false,
+ endOnTick: false,
+ gridLineWidth: 1,
+ tickPixelInterval: 72,
+ minPadding: 0.1,
+ minRange: 0.1,
+ crosshair: {
+ color: 'red',
+ snap: false,
+ zIndex: 4,
+ },
+ labels: {
+ enabled: true,
+ style: { fontSize: '11px' },
+ x: -7,
+ },
+ },
+ xAxis: {
+ startOnTick: false,
+ endOnTick: false,
+ lineWidth: 0,
+ tickWidth: 0,
+ minRange: 0.1,
+ gridLineWidth: 1,
+ labels: { style: { fontSize: '11px' }, y: 14 },
+ },
+ series: [
+ {
+ data: [['', 2060, 2000]],
+ type: 'dumbbell',
+ name: 'Surface_26: Cement',
+ color: 'lightgray',
+ groupPadding: 0.7,
+ connectorWidth: 14,
+ marker: {
+ radius: 0,
+ },
+ },
+ {
+ data: [['', 2060, 2000]],
+ type: 'dumbbell',
+ name: 'Surface_26: Tubular',
+ color: 'black',
+ zIndex: 1,
+ groupPadding: 0.7,
+ connectorWidth: 3,
+ marker: {
+ radius: 0,
+ },
+ lowMarker: {
+ radius: 5,
+ fillColor: 'black',
+ symbol: 'flag',
+ },
+ },
+ {
+ data: [['', 2791.96, 2000]],
+ type: 'dumbbell',
+ name: 'Phase_16: Cement',
+ color: 'lightgray',
+ groupPadding: 0.7,
+ connectorWidth: 14,
+ marker: {
+ radius: 0,
+ },
+ },
+ {
+ data: [['', 2791.96, 2000]],
+ type: 'dumbbell',
+ name: 'Phase_16: Tubular',
+ color: 'black',
+ zIndex: 1,
+ groupPadding: 0.7,
+ connectorWidth: 3,
+ marker: {
+ radius: 0,
+ },
+ lowMarker: {
+ radius: 5,
+ fillColor: 'black',
+ symbol: 'flag',
+ },
+ },
+ {
+ data: [['', 4500, 4000]],
+ type: 'dumbbell',
+ name: 'Phase_13_375: Cement',
+ color: 'lightgray',
+ groupPadding: 0.7,
+ connectorWidth: 14,
+ marker: {
+ radius: 0,
+ },
+ },
+ {
+ data: [['', 4500, 2000]],
+ type: 'dumbbell',
+ name: 'Phase_13_375: Tubular',
+ color: 'black',
+ zIndex: 1,
+ groupPadding: 0.7,
+ connectorWidth: 3,
+ marker: {
+ radius: 0,
+ },
+ lowMarker: {
+ radius: 5,
+ fillColor: 'black',
+ symbol: 'flag',
+ },
+ },
+ {
+ data: [['', 5250, 4650]],
+ type: 'dumbbell',
+ name: 'Phase_10_74: Cement',
+ color: 'lightgray',
+ groupPadding: 0.7,
+ connectorWidth: 14,
+ marker: {
+ radius: 0,
+ },
+ },
+ {
+ data: [['', 5250, 4400]],
+ type: 'dumbbell',
+ name: 'Phase_10_74: Tubular',
+ color: 'black',
+ zIndex: 1,
+ groupPadding: 0.7,
+ connectorWidth: 3,
+ marker: {
+ radius: 0,
+ },
+ lowMarker: {
+ radius: 5,
+ fillColor: 'black',
+ symbol: 'flag',
+ },
+ },
+ ],
+ };
+}
diff --git a/src/app/map-chart/map-chart.component.ts b/src/app/map-chart/map-chart.component.ts
index 44bd377..475beb6 100644
--- a/src/app/map-chart/map-chart.component.ts
+++ b/src/app/map-chart/map-chart.component.ts
@@ -17,7 +17,8 @@ import { HighchartsChartComponent, providePartialHighcharts } from 'highcharts-a
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MapChartComponent {
- public readonly worldMap = httpResource('/highcharts/world.geo.json');
+ // https://code.highcharts.com/mapdata/
+ public readonly worldMap = httpResource('https://code.highcharts.com/mapdata/custom/world.topo.json');
public readonly chartMap = computed(() => {
return {
chart: {
diff --git a/src/app/tilemap-chart/tilemap-chart.component.css b/src/app/tilemap-chart/tilemap-chart.component.css
new file mode 100644
index 0000000..6a487ef
--- /dev/null
+++ b/src/app/tilemap-chart/tilemap-chart.component.css
@@ -0,0 +1,11 @@
+h2 {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 1.25rem;
+ margin: 0 0 1.5rem 0;
+}
+
+.main {
+ width: 100%;
+ height: 650px;
+ display: block;
+}
diff --git a/src/app/tilemap-chart/tilemap-chart.component.html b/src/app/tilemap-chart/tilemap-chart.component.html
new file mode 100644
index 0000000..d976931
--- /dev/null
+++ b/src/app/tilemap-chart/tilemap-chart.component.html
@@ -0,0 +1,10 @@
+
+ Demo #5: Highcharts Tile Maps
+
+
diff --git a/src/app/tilemap-chart/tilemap-chart.component.ts b/src/app/tilemap-chart/tilemap-chart.component.ts
new file mode 100644
index 0000000..14cf508
--- /dev/null
+++ b/src/app/tilemap-chart/tilemap-chart.component.ts
@@ -0,0 +1,103 @@
+import { Component, ChangeDetectionStrategy } from '@angular/core';
+import { HighchartsChartComponent, providePartialHighcharts, ChartConstructorType } from 'highcharts-angular';
+
+@Component({
+ selector: 'app-tilemap-chart',
+ imports: [HighchartsChartComponent],
+ templateUrl: './tilemap-chart.component.html',
+ styleUrl: './tilemap-chart.component.css',
+ providers: [
+ providePartialHighcharts({
+ modules: () => [import('highcharts/esm/modules/map'), import('highcharts/esm/modules/tilemap')],
+ }),
+ ],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class TilemapChartComponent {
+ public get chartOptions(): Highcharts.Options {
+ return {
+ chart: {
+ type: 'tilemap',
+ inverted: true,
+ height: '80%',
+ },
+ title: {
+ text: 'My Title',
+ },
+ xAxis: {
+ visible: false,
+ },
+ yAxis: {
+ visible: false,
+ },
+ colorAxis: {
+ dataClasses: [
+ {
+ from: 0,
+ to: 1000000,
+ color: '#3b528b',
+ name: '< 1M',
+ },
+ {
+ from: 1000000,
+ to: 5000000,
+ color: '#21918c',
+ name: '1M - 5M',
+ },
+ {
+ from: 5000000,
+ to: 20000000,
+ color: '#5ec962',
+ name: '5M - 20M',
+ },
+ {
+ from: 20000000,
+ color: '#fde725',
+ name: '> 20M',
+ },
+ ],
+ },
+ legend: {
+ enabled: false,
+ },
+ tooltip: {
+ headerFormat: '',
+ pointFormat: 'Population de {point.name}: {point.value}',
+ },
+ plotOptions: {
+ tilemap: {
+ tileShape: 'hexagon',
+ dataLabels: {
+ enabled: true,
+ format: '{point.hc-a2}',
+ style: {
+ textOutline: 'none',
+ },
+ },
+ },
+ },
+ series: [
+ {
+ type: 'tilemap',
+ name: 'Population',
+ data: this.getTilemapData(),
+ },
+ ],
+ };
+ }
+
+ private getTilemapData(): any[] {
+ return [
+ { 'hc-a2': 'CA', name: 'California', x: 5, y: 2, value: 38965193 },
+ { 'hc-a2': 'TX', name: 'Texas', x: 7, y: 4, value: 30503301 },
+ { 'hc-a2': 'FL', name: 'Florida', x: 8, y: 8, value: 22610726 },
+ { 'hc-a2': 'NY', name: 'New York', x: 2, y: 9, value: 19571216 },
+ { 'hc-a2': 'IL', name: 'Illinois', x: 3, y: 6, value: 12882135 },
+ { 'hc-a2': 'PA', name: 'Pennsylvania', x: 3, y: 8, value: 12801989 },
+ ];
+ }
+
+ public chartConstructor: ChartConstructorType = 'chart';
+ public updateFlag = false;
+ public oneToOneFlag = true;
+}