
Syncfusion Angular Heatmap
- 165 installs
- Updated August 4, 2026
- syncfusion/angular-ui-components-skills
Use syncfusion-angular-heatmap for development tasks
About
syncfusion-angular-heatmap: A skill for development. This provides functionality for development workflows.
- syncfusion-angular-heatmap
Syncfusion Angular Heatmap by the numbers
- 165 all-time installs (skills.sh)
- +11 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #2,345 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/angular-ui-components-skills --skill syncfusion-angular-heatmapAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 165 |
|---|---|
| Last updated | August 4, 2026 |
| Repository | syncfusion/angular-ui-components-skills ↗ |
What it does
Use syncfusion-angular-heatmap for development tasks
Files
Implementing HeatMap
The HeatMap Chart component is a powerful visualization tool for displaying two-dimensional data where values are represented through color gradients or fixed colors. Perfect for analyzing patterns, correlations, and distributions in matrix data, time-series heatmaps, and any scenario requiring color-encoded data representation.
When to Use This Skill
- Data Matrix Visualization: Display 2D data arrays with color-coded cells
- Correlation Analysis: Visualize relationships between multiple variables
- Time-Series Heatmaps: Show patterns over time (e.g., hourly/daily activity)
- Category Comparison: Compare performance across categories and metrics
- Intensity Mapping: Display heatmaps with gradient colors representing value intensity
- Interactive Selection: Enable user selection of cells with tooltips and event handling
- Accessibility Requirements: Implement WCAG-compliant heatmaps with ARIA support
- Custom Styling: Apply themes, palettes, and custom rendering (SVG/Canvas)
- Bubble Heatmaps: Visualize data as bubbles with size and color encoding
- Large Datasets: Handle auto-switching between SVG and Canvas rendering modes
Component Overview
HeatMap is a flexible, high-performance visualization component with rich customization:
- Axis Types: Numeric, Categorical, and DateTime axes
- Data Binding: JSON arrays and 2D matrix formats
- Rendering Modes: Auto-switching SVG (small data) and Canvas (large data)
- Interactive Features: Cell selection, tooltips, data labels, events
- Customization: Color palettes, themes, cell styling, borders
- Accessibility: WCAG compliance, ARIA attributes, keyboard navigation
- Legend Support: Automatic and custom legend rendering
- Bubble Variant: Alternative bubble heatmap visualization
- Standalone Ready: Compatible with Angular 19+ standalone components
Documentation and Navigation Guide
API Reference
📄 Read: references/api-reference.md
Getting Started & Installation
📄 Read: references/getting-started.md
- Installing @syncfusion/ej2-angular-heatmap package
- Module imports for Angular standalone and traditional modules
- Creating your first heatmap
- Basic data binding setup
- Verifying installation works
Data Binding & Formats
📄 Read: references/data-binding.md
- JSON array format for structured data
- 2D array format for matrix data
- DataManager for remote data
- Binding x/y axis fields
- Live data updates and dynamic binding
Axes Configuration
📄 Read: references/axes-configuration.md
- X/Y axis types: Numeric, Categorical, DateTime
- Axis labels, titles, and intervals
- Inverted axes and opposed positions
- Axis customization and properties
- Working with date/time data
Legend Rendering
📄 Read: references/legend-rendering.md
- Legend positioning and alignment
- Legend sizing and appearance
- Custom legend data display
- Interactive legend behavior
- Legend label formatting
Visual Customization & Rendering
📄 Read: references/visual-customization.md
- Color palettes and themes
- SVG vs Canvas rendering modes
- Cell styling and borders
- Gradient and fixed colors
- Bubble heatmap variations
- Responsive design
Interactivity, Events & Accessibility
📄 Read: references/interactivity-events.md
- Cell selection modes and events
- Tooltip customization and templating
- Data labels and formatting
- Cell click and selection handlers
- WCAG accessibility compliance
- ARIA attributes and keyboard navigation
- Screen reader support
Advanced Features & How-tos
📄 Read: references/advanced-features.md
- EJ1 to EJ2 migration guide
- How-to: Custom tooltip templates
- How-to: Legend customization
- How-to: Performance optimization for large datasets
- Combining selection with data updates
- Multi-dimensional data representation
Quick Start
Minimal HeatMap Setup
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule } from '@syncfusion/ej2-angular-heatmap';
@Component({
imports: [HeatMapModule],
standalone: true,
selector: 'app-heatmap',
template: `
<ejs-heatmap id='heatmap-container'
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'>
</ejs-heatmap>
`,
encapsulation: ViewEncapsulation.None
})
export class HeatMapComponent {
dataSource: any[] = [
{ ProductName: 'Milk', Year: 2005, Sales: 21, Quarter: 'Q1' },
{ ProductName: 'Milk', Year: 2006, Sales: 22, Quarter: 'Q1' },
{ ProductName: 'Milk', Year: 2007, Sales: 23, Quarter: 'Q1' },
{ ProductName: 'Bread', Year: 2005, Sales: 18, Quarter: 'Q1' },
{ ProductName: 'Bread', Year: 2006, Sales: 19, Quarter: 'Q1' },
{ ProductName: 'Bread', Year: 2007, Sales: 20, Quarter: 'Q1' }
];
xAxis: any = {
labels: ['2005', '2006', '2007'],
type: 'Labels',
opposedPosition: true
};
yAxis: any = {
labels: ['Milk', 'Bread'],
type: 'Labels'
};
}Common Patterns
Pattern 1: Sales Performance Matrix
Display product sales by year with color gradient representing performance levels.
dataSource = [
{ Product: 'Product A', Year: 2020, Sales: 50 },
{ Product: 'Product A', Year: 2021, Sales: 75 },
{ Product: 'Product B', Year: 2020, Sales: 60 },
{ Product: 'Product B', Year: 2021, Sales: 85 }
];
xAxis = { labels: ['2020', '2021'], type: 'Labels' };
yAxis = { labels: ['Product A', 'Product B'], type: 'Labels' };When: Comparing performance metrics across multiple dimensions Why: Color-coded cells make patterns immediately visible
Pattern 2: Time-Series Activity Heatmap
Show hourly or daily activity patterns with DateTime axis.
<ejs-heatmap [xAxis]='{ type: "DateTime", intervalType: "Days" }'
[yAxis]='{ labels: ["12 AM", "1 AM", "2 AM", "3 AM"] }'>
</ejs-heatmap>When: Analyzing time-based patterns (traffic, usage, activity) Why: DateTime axis automatically formats and scales time data
Pattern 3: Interactive Cell Selection
Enable users to select cells and respond to selection events.
<ejs-heatmap [cellSettings]='{ border: { width: 1 } }'
(cellSelected)='onCellSelect($event)'
[allowSelection]='true'>
</ejs-heatmap>
onCellSelect(event: any) {
console.log('Selected cell:', event.cellCollection);
}When: Building interactive dashboards with drill-down capability Why: Selection events enable dynamic filtering and detail views
Pattern 4: Custom Tooltip with Data Labels
Display detailed information on hover and within cells.
<ejs-heatmap [tooltip]='{ enable: true }'>
<e-heatmap-cellsettings [showLabel]='true'
[labelFormat]='{ format: "{value}" }'>
</e-heatmap-cellsettings>
</ejs-heatmap>When: Users need detailed values without clicking Why: Tooltips reduce cognitive load while maintaining clean appearance
Pattern 5: Bubble Heatmap Variation
Use bubbles instead of cells for alternative visualization.
<ejs-heatmap [renderingMode]='BubbleHeatMap'>
<e-heatmap-cellsettings showLabel='true' bubbleType='Size'>
</e-heatmap-cellsettings>
</ejs-heatmap>When: Emphasizing value magnitude through bubble size Why: Bubble size adds an additional visual dimension
Key Props
Data and Axes
dataSource: Array of data objects (JSON format)xAxis: X-axis configuration (Labels, Numeric, DateTime)yAxis: Y-axis configuration (Labels, Numeric, DateTime)valueBound: Range of color gradient values [min, max]cellSettings: Cell appearance and labels
Legend and Display
legendSettings: Legend positioning, alignment, and appearancepalette: Color scheme array or predefined themetitle: Heatmap titleheight,width: Chart dimensions
Interactivity
allowSelection: Enable/disable cell selectioncellSelected: Event fired on cell selectioncellRender: Customize cell appearancecellHover: Hover event for cellstooltipSettings: Tooltip display configuration
Rendering
renderingMode: SVG or Canvas modecellBorder: Cell border configurationshowGradientLegend: Display gradient legend
Common Use Cases
Use Case 1: Product Performance Dashboard
Display quarterly sales metrics across products using a heatmap. Color intensity shows performance level. Users click cells to see drill-down details.
Use Case 2: Server Activity Monitor
Track server CPU/memory usage by hour of day and day of week. Time-series heatmap with DateTime axes. Auto-switching Canvas mode for large datasets.
Use Case 3: Correlation Matrix
Visualize statistical correlations between multiple variables. Color gradients represent correlation strength. Hover tooltips show exact values.
Use Case 4: Website Traffic Heatmap
Analyze visitor traffic patterns by page and time. Bubble heatmap shows traffic volume. Selection enables filtering by time periods.
Advanced Features & How-tos
API Reference: references/api-reference.md
Table of Contents
- Table of Contents
- EJ1 to EJ2 Migration
- Key Changes Summary
- Complete Migration Example
- EJ1 Code
- EJ2 Code
- Migration Checklist
- Custom Tooltip Templates
- Basic Custom Template
- Tooltip with Calculated Values
- Format Data in Tooltip
- Legend Customization
- Legend Configuration
- Dynamic Legend Updates
- Performance Optimization
- Data Aggregation
- Canvas Rendering for Large Datasets
- Lazy Loading Pattern
- Selection with Data Updates
- Selection-Triggered Details
- Multi-dimensional Data
- 3D Data via Bubble Size
- Layered Heatmaps
EJ1 to EJ2 Migration
Guide for migrating from Syncfusion EJ1 HeatMap to EJ2.
Key Changes Summary
| EJ1 | EJ2 | Notes |
|---|---|---|
ej-heatmap | ejs-heatmap | Component tag changed |
itemsSource | [dataSource] | Property binding syntax |
colorMappingCollection | paletteSettings | Color configuration restructured |
heatmapCell.showContent | cellSettings.showLabel | Same property |
| Older templating | Interpolation syntax | Uses Angular template syntax |
Complete Migration Example
EJ1 Code
// EJ1 - Old approach
declare let ejHeatMap: any;
ngAfterViewInit() {
$('#heatmap').ejHeatmap({
datasource: this.data,
colorMappings: [
{ value: 0, color: '#FF0000' },
{ value: 100, color: '#00FF00' }
]
});
}EJ2 Code
// EJ2 - New approach
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { HeatMapModule} from '@syncfusion/ej2-angular-heatmap'
import { LegendService} from '@syncfusion/ej2-angular-heatmap'
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
imports: [ HeatMapModule ],
providers: [ LegendService],
standalone: true,
selector: 'my-app',
template:
`<ejs-heatmap id='container' style="display:block;" [dataSource]='dataSource' [xAxis]='xAxis' [yAxis]='yAxis'
[titleSettings]='titleSettings' [paletteSettings]='paletteSettings' [legendSettings]='legendSettings'>
</ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent{
dataSource: Object[] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68],
[99, 28, 22, 4, 66, 90],
[14, 26, 97, 69, 69, 3],
[7, 46, 47, 47, 88, 6],
[41, 55, 73, 23, 3, 79],
[56, 69, 21, 86, 3, 33],
[45, 7, 53, 81, 95, 79],
[60, 77, 74, 68, 88, 51],
[25, 25, 10, 12, 78, 14],
[25, 56, 55, 58, 12, 82],
[74, 33, 88, 23, 86, 59]];
titleSettings: Object = {
text: 'Sales Revenue per Employee (in 1000 US$)',
textStyle: {
size: '15px',
fontWeight: '500',
fontStyle: 'Normal',
fontFamily: 'Segoe UI'
}
};
xAxis: Object = {
labels: ['Nancy', 'Andrew', 'Janet', 'Margaret', 'Steven',
'Michael', 'Robert', 'Laura', 'Anne', 'Paul', 'Karin', 'Mario'],
};
yAxis: Object = {
labels: ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'],
};
public paletteSettings: Object = {
palette: [
{ color: '#C06C84'},
{ color: '#6C5B7B'},
{ color: '#355C7D'}
],
type: "Gradient"
};
public legendSettings: Object = {
visible: true,
};
}Migration Checklist
- [ ] Update imports:
HeatMapModulefrom@syncfusion/ej2-angular-heatmap - [ ] Convert jQuery initialization to component template
- [ ] Update property binding:
itemsSource→[dataSource] - [ ] Migrate
colorMappingCollection→paletteSettings - [ ] Update event handlers:
cellClick→(cellClick) - [ ] Test data binding and rendering
- [ ] Verify accessibility features work
- [ ] Update component styling
Custom Tooltip Templates
Create rich, interactive tooltips with custom templates.
Basic Custom Template
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { HeatMapModule} from '@syncfusion/ej2-angular-heatmap'
import { TooltipService} from '@syncfusion/ej2-angular-heatmap'
import { Component, ViewEncapsulation } from '@angular/core';
import { ITooltipEventArgs } from '@syncfusion/ej2-angular-heatmap';
@Component({
imports: [ HeatMapModule ],
providers: [TooltipService],
standalone: true,
selector: 'my-app',
template:
`<ejs-heatmap id='container' style="display:block;" [dataSource]='dataSource' [xAxis]='xAxis' [yAxis]='yAxis'
[titleSettings]='titleSettings' [cellSettings]='cellSettings' (tooltipRender)='tooltipRender($event)'>
</ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent{
dataSource: Object[] = [
[0.72, 0.71, 0.71, 0.67, 0.72, 0.53, 0.53, 0.56, 0.58, 0.56],
[2.28, 2.29, 2.09, 1.84, 1.64, 1.49, 1.49, 1.39, 1.32, 1.23],
[2.02, 2.17, 2.30, 2.39, 2.36, 2.52, 2.62, 2.57, 2.57, 2.74],
[3.21, 3.26, 3.45, 3.47, 3.42, 3.34, 3.14, 2.83, 2.64, 2.61],
[3.22, 3.13, 3.04, 2.95, 2.69, 2.49, 2.27, 2.18, 2.06, 1.87],
[3.30, 3.39, 3.40, 3.48, 3.60, 3.67, 3.73, 3.79, 3.79, 4.07],
[5.80, 5.74, 5.64, 5.44, 5.18, 5.08, 5.07, 5.00, 5.35, 5.47],
[6.91, 7.40, 8.13, 8.80, 9.04, 9.24, 9.43, 9.35, 9.49, 9.69]];
titleSettings: Object = {
text: 'Crude Oil Production of Non-OPEC Countries (in Million barrels per day)',
textStyle: {
size: '15px',
fontWeight: '500',
fontStyle: 'Normal',
fontFamily: 'Segoe UI'
}
};
xAxis: Object = {
labels: ['Canada', 'China', 'Egypt', 'Mexico', 'Norway', 'Russia', 'UK', 'USA']
};
yAxis: Object = {
labels: ['2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010'],
};
public cellSettings: Object = {
showLabel: false,
};
public showTooltip: Boolean = true;
public tooltipRender(args: ITooltipEventArgs): void {
args.content = ['In ' + args.yLabel + ', the ' + args.xLabel + ' produced ' + args.value + ' million barrels per day'];
};
}Tooltip with Calculated Values
tooltipSettings: Object = {
template: '<div>' +
'<b>${xValue} - ${yValue}</b><br/>' +
'Revenue: $${value}<br/>' +
'Growth: <span style="color: ${value > 45000 ? "green" : "red"}">' +
'${value > 45000 ? "↑ High" : "↓ Low"}' +
'</span>' +
'</div>'
};Format Data in Tooltip
tooltipSettings: Object = {
template: (args: any) => {
// Access raw data
const dataItem = args.data;
return `
<div class='tooltip-content'>
<p><strong>${args.xValue}</strong> - <strong>${args.yValue}</strong></p>
<p>Sales: $${this.formatNumber(args.value)}</p>
<p>Units: ${dataItem.Units}</p>
<p>Avg: ${(args.value / dataItem.Units).toFixed(2)}</p>
</div>
`;
}
};
formatNumber(num: number): string {
return num.toLocaleString('en-US');
}Legend Customization
Advanced legend configuration and styling.
Legend Configuration
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { HeatMapModule} from '@syncfusion/ej2-angular-heatmap'
import { LegendService} from '@syncfusion/ej2-angular-heatmap'
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
imports: [ HeatMapModule ],
providers: [ LegendService ],
standalone: true,
selector: 'my-app',
template:
`<ejs-heatmap id='container' style="display:block;" [dataSource]='dataSource' [xAxis]='xAxis' [yAxis]='yAxis' [titleSettings]='titleSettings' [paletteSettings}='paletteSettings' [legendSettings]='legendSettings' [cellSettings]='cellSettings'>
</ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent{
dataSource: Object[] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68],
[99, 28, 22, 4, 66, 90],
[14, 26, 97, 69, 69, 3],
[7, 46, 47, 47, 88, 6],
[41, 55, 73, 23, 3, 79],
[56, 69, 21, 86, 3, 33],
[45, 7, 53, 81, 95, 79],
[60, 77, 74, 68, 88, 51],
[25, 25, 10, 12, 78, 14],
[25, 56, 55, 58, 12, 82],
[74, 33, 88, 23, 86, 59]
];
titleSettings: Object = {
text: 'Sales Revenue per Employee (in 1000 US$)',
textStyle: {
size: '15px',
fontWeight: '500',
fontStyle: 'Normal',
fontFamily: 'Segoe UI'
}
};
xAxis: Object = {
labels: ['Nancy', 'Andrew', 'Janet', 'Margaret', 'Steven',
'Michael', 'Robert', 'Laura', 'Anne', 'Paul', 'Karin', 'Mario'],
};
yAxis: Object = {
labels: ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'],
};
public cellSettings: Object = {
showLabel: false,
};
public paletteSettings: Object = {
palette: [
{ value: 0, color: '#C2E7EC' },
{ value: 10, color: '#AEDFE6' },
{ value: 20, color: '#9AD7E0' },
{ value: 30, color: '#72C7D4' },
{ value: 40, color: '#5EBFCE' },
{ value: 50, color: '#4AB7C8' },
{ value: 60, color: '#309DAE' },
{ value: 70, color: '#2B8C9B' },
{ value: 80, color: '#206974' },
{ value: 90, color: '#15464D' },
{ value: 100, color: '#000000' },
],
};
public legendSettings: Object = {
position: 'Right',
};
}Dynamic Legend Updates
import { Component, ViewChild, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, LegendService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [LegendService],
template: `
<div>
<button (click)="updateLegend()">Update Legend</button>
<ejs-heatmap
#heatmap
[dataSource]="dataSource"
[xAxis]="xAxis"
[yAxis]="yAxis"
[legendSettings]="legendSettings">
</ejs-heatmap>
</div>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
dataSource: number[][] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68],
[99, 28, 22, 4, 66, 90],
[14, 26, 97, 69, 69, 3],
[7, 46, 47, 47, 88, 6],
[41, 55, 73, 23, 3, 79],
[56, 69, 21, 86, 3, 33],
[45, 7, 53, 81, 95, 79],
[60, 77, 74, 68, 88, 51],
[25, 25, 10, 12, 78, 14],
[25, 56, 55, 58, 12, 82],
[74, 33, 88, 23, 86, 59]
];
xAxis: Object = { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'] };
yAxis: Object = { labels: ['2010', '2011', '2012', '2013', '2014', '2015'] };
legendSettings: Object = {
position: 'Right'
};
updateLegend() {
this.legendSettings = { position: 'Bottom' };
}
}Performance Optimization
Optimize heatmap for large datasets.
Data Aggregation
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, TooltipService } from '@syncfusion/ej2-angular-heatmap';
// ✅ Define interface for raw data points
interface DataPoint {
category: string;
value: number;
}
// ✅ Define interface for aggregated data points
interface AggregatedPoint {
x: number;
y: string;
value: number;
}
@Component({
selector: 'my-app',
imports: [HeatMapModule],
providers:[TooltipService],
standalone: true,
template: `
<ejs-heatmap id="heatmap"
[dataSource]="aggregatedData"
renderingMode="Canvas">
</ejs-heatmap>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
rawData: DataPoint[] = [];
aggregatedData: AggregatedPoint[] = [];
ngOnInit() {
// Load and aggregate large dataset
this.rawData = this.loadLargeDataset();
this.aggregatedData = this.aggregateData();
}
aggregateData(): AggregatedPoint[] {
const aggregated: AggregatedPoint[] = [];
const groupSize = 10;
for (let i = 0; i < this.rawData.length; i += groupSize) {
const group = this.rawData.slice(i, i + groupSize);
const avg =
group.reduce((sum, item) => sum + item.value, 0) / group.length;
aggregated.push({
x: Math.floor(i / groupSize),
y: group[0].category,
value: avg
});
}
return aggregated;
}
loadLargeDataset(): DataPoint[] {
// Simulate loading 100k+ records
const data: DataPoint[] = [];
for (let i = 0; i < 10000; i++) {
data.push({
category: `Cat${Math.floor(i / 1000)}`,
value: Math.random() * 100
});
}
return data;
}
}Canvas Rendering for Large Datasets
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true, // standalone component
imports: [HeatMapModule],
template: `
<ejs-heatmap id="heatmap"
[dataSource]="dataSource"
renderingMode="Canvas"
[xAxis]="xAxis"
[yAxis]="yAxis">
</ejs-heatmap>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
dataSource: { x: number; y: number; value: number }[] = [];
// ✅ Moved axis configs into class
xAxis = { type: 'Numeric', minimum: 0, maximum: 999 };
yAxis = { type: 'Numeric', minimum: 0, maximum: 999 };
ngOnInit() {
// Generate 1 million data points
for (let x = 0; x < 1000; x++) {
for (let y = 0; y < 1000; y++) {
this.dataSource.push({
x: x,
y: y,
value: Math.random() * 100
});
}
}
// Canvas mode will be auto-selected for performance
}
}Lazy Loading Pattern
import { Component, ViewChild, OnInit } from '@angular/core';
import { HeatMapComponent, HeatMapModule, TooltipService, LegendService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true, // Required for the imports array below
imports: [HeatMapModule],
providers: [TooltipService, LegendService],
template: `
<div class="control-section">
<button (click)='loadMore()' style="margin-bottom: 10px;">Load More Data</button>
<ejs-heatmap #heatmap
[dataSource]='displayData'
[dataSourceSettings]='dataSourceSettings'
[xAxis]='xAxis'
[yAxis]='yAxis'>
</ejs-heatmap>
</div>
`
})
export class AppComponent implements OnInit {
@ViewChild('heatmap') heatmapObj!: HeatMapComponent;
allData: any[] = [];
displayData: any[] = [];
pageSize: number = 100;
currentPage: number = 0;
// Define data mapping for JSON objects
public dataSourceSettings = {
isJsonData: true,
adaptorType: 'Cell',
xDataMapping: 'x',
yDataMapping: 'y',
valueMapping: 'value'
};
public xAxis = { labels: ['0', '25', '50', '75', '99'] };
public yAxis = { labels: ['0', '2', '4', '6', '8', '9'] };
ngOnInit() {
this.allData = this.generateData(1000);
this.loadNextPage();
}
loadNextPage() {
const start = 0; // Cumulative loading
const end = (this.currentPage + 1) * this.pageSize;
if (end <= this.allData.length) {
// Update displayData with a new reference to trigger change detection
this.displayData = [...this.allData.slice(start, end)];
this.currentPage++;
// Safety refresh if manual update is needed
if (this.heatmapObj) {
//this.heatmapObj.refresh();
}
}
}
loadMore() {
this.loadNextPage();
}
generateData(count: number): any[] {
const data = [];
for (let i = 0; i < count; i++) {
data.push({
x: (i % 100).toString(),
y: Math.floor(i / 100).toString(),
value: Math.floor(Math.random() * 100)
});
}
return data;
}
}Selection with Data Updates
Handle cell selection and respond with data updates.
Selection-Triggered Details
import { Component, ViewChild, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HeatMapComponent, HeatMapModule, TooltipService, LegendService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule, CommonModule],
providers: [TooltipService, LegendService],
template: `
<div style='display: flex; gap: 20px; padding: 20px; font-family: Segoe UI, sans-serif;'>
<div style='flex: 1; border: 1px solid #ddd; padding: 10px;'>
<h3>Heatmap</h3>
<ejs-heatmap #heatmap
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[allowSelection]='true'
(cellSelected)='onCellSelect($event)'>
</ejs-heatmap>
</div>
<div style='flex: 1; border: 1px solid #ddd; padding: 10px; background: #f9f9f9;'>
<h3>Details for {{ selectedX || '...' }} - {{ selectedY || '...' }}</h3>
<div *ngIf='selectedDetails; else noSelection'>
<p><strong>Value:</strong> {{ selectedDetails.value }}</p>
<p><strong>Status:</strong> {{ selectedDetails.status }}</p>
<p><strong>Trend:</strong> {{ selectedDetails.trend }}</p>
</div>
<ng-template #noSelection>
<p style="color: #666;">Click a cell to see specific details.</p>
</ng-template>
</div>
</div>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild('heatmap') heatmapObj!: HeatMapComponent;
// Use the provided 2D number array
public dataSource: number[][] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68],
[99, 28, 22, 4, 66, 90],
[14, 26, 97, 69, 69, 3],
[7, 46, 47, 47, 88, 6],
[41, 55, 73, 23, 3, 79],
[56, 69, 21, 86, 3, 33],
[45, 7, 53, 81, 95, 79],
[60, 77, 74, 68, 88, 51],
[25, 25, 10, 12, 78, 14],
[25, 56, 55, 58, 12, 82],
[74, 33, 88, 23, 86, 59]
];
public xAxis: Object = {
valueType: 'Category',
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
};
public yAxis: Object = {
valueType: 'Category',
labels: ['2010', '2011', '2012', '2013', '2014', '2015', '2016', '2017', '2018', '2019', '2020', '2021']
};
selectedX: string = '';
selectedY: string = '';
selectedDetails: any = null;
onCellSelect(event: any) {
// Handle selection data from the event
if (event.data && event.data.length > 0) {
const cell = event.data[0];
this.selectedX = cell.xLabel;
this.selectedY = cell.yLabel;
this.selectedDetails = this.getDetailedInfo(cell.value as number);
}
}
getDetailedInfo(value: number): any {
return {
value: value,
status: value > 50 ? 'High' : 'Low',
trend: value > 75 ? '↑ Peaking' : '↓ Stable'
};
}
}Multi-dimensional Data
Represent more than 2 dimensions in a heatmap.
3D Data via Bubble Size
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { HeatMapModule} from '@syncfusion/ej2-angular-heatmap'
import { LegendService, AdaptorService, TooltipService} from '@syncfusion/ej2-angular-heatmap'
import { Component, ViewEncapsulation } from '@angular/core';
import { BubbleTooltipData, ITooltipEventArgs } from '@syncfusion/ej2-angular-heatmap';
@Component({
imports: [ HeatMapModule ],
providers: [ LegendService, AdaptorService, TooltipService],
standalone: true,
selector: 'my-app',
template:
`<ejs-heatmap id='container' style="display:block;" [dataSource]='dataSource' [xAxis]='xAxis' [yAxis]='yAxis'
[titleSettings]='titleSettings' [paletteSettings]='paletteSettings' [cellSettings]='cellSettings' [legendSettings]='legendSettings' (tooltipRender)='tooltipRender($event)'>
</ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
dataSource: Object[] = [
[[4, 39], [3, 8], [1, 3], [1, 10], [4, 4], [2, 15]],
[[4, 28], [5, 92], [5, 73], [3, 1], [3, 4], [4, 126]],
[[4, 45], [5, 152], [0, 44], [4, 54], [5, 243], [2, 45]]
];
titleSettings: Object = {
text: 'Commercial Aviation Accidents and Fatalities by year 2012 - 2017',
textStyle: {
size: '15px',
fontWeight: '500',
fontStyle: 'Normal',
fontFamily: 'Segoe UI'
}
};
xAxis: Object = {
labels: ['2017', '2016', '2015'],
};
yAxis: Object = {
labels: ['Jan-Feb', 'Mar-Apr', 'May-Jun', 'Jul-Aug', 'Sep-Oct', 'Nov-Dec'],
};
public paletteSettings: Object = {
palette: [
{ color: '#C06C84' },
{ color: '#6C5B7B' },
{ color: '#355C7D' }
],
type: "Gradient"
};
public cellSettings: Object = {
border: {
width: 1
},
tileType: 'Bubble',
bubbleType: 'SizeAndColor'
};
public legendSettings: Object = {
visible: true,
};
public tooltipRender(args: ITooltipEventArgs): void {
args.content = ['Year ' + ' : ' + args.xLabel + '<br/>' + 'Months ' + ' : ' + args.yLabel + '<br/>'
+ 'Accidents ' + ' : ' + (args.value as BubbleTooltipData[])[0].bubbleData + '<br/>' + 'Fatalities ' + ' : '
+ (args.value as BubbleTooltipData[])[1].bubbleData];
};
}Layered Heatmaps
import { Component, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HeatMapModule, TooltipService, LegendService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule, CommonModule],
providers: [TooltipService, LegendService],
template: `
<div style="padding: 20px; font-family: sans-serif;">
<div style="margin-bottom: 20px;">
<label style="font-weight: bold; margin-right: 10px;">Select Layer:</label>
<select (change)='changeLayer($event)' style="padding: 5px; border-radius: 4px;">
<option *ngFor='let layer of layers' [value]='layer'>
{{ layer }}
</option>
</select>
</div>
<div style="border: 1px solid #ddd; padding: 15px; border-radius: 8px;">
<h3 style="margin-top: 0;">Layer: {{ selectedLayer }}</h3>
<ejs-heatmap id='heatmap'
[dataSource]='currentDataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'>
</ejs-heatmap>
</div>
</div>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
public layers: string[] = ['Revenue', 'Units', 'Profit'];
public selectedLayer: string = 'Revenue';
// 2D Array Data Source
public allData: { [key: string]: number[][] } = {
'Revenue': [
[45000, 38000, 52000],
[32000, 41000, 48000]
],
'Units': [
[150, 120, 180],
[110, 140, 165]
],
'Profit': [
[15000, 12000, 19000],
[9000, 13000, 15500]
]
};
public currentDataSource: number[][] = this.allData['Revenue'];
public xAxis: Object = {
labels: ['Q1', 'Q2', 'Q3']
};
public yAxis: Object = {
labels: ['Product A', 'Product B']
};
changeLayer(event: any) {
this.selectedLayer = event.target.value;
// Trigger update by changing the reference
this.currentDataSource = this.allData[this.selectedLayer];
}
}````markdown
HeatMap API Reference
Base URL: https://ej2.syncfusion.com/angular/documentation/api/heatmap/index-default
This file lists the primary properties, methods and events for the Angular ejs-heatmap component (curated) and links to the official API index above for full details.
Key Properties
- `allowSelection` : boolean — enable/disable cell selection
- `backgroundColor` : string — container background color
- `cellSettings` :
CellSettingsModel— border, label and bubble settings for cells - `dataSource` : Object[] | 2D array — data for rendering cells
- `legendSettings` :
LegendSettingsModel— legend position and appearance - `paletteSettings` :
PaletteSettingsModel— color palette / gradient configuration - `renderingMode` :
DrawType—SVGorCanvasrendering mode - `tooltipSettings` :
TooltipSettingsModel— tooltip templates and behavior - `xAxis` :
AxisModel— configuration for X axis (Labels/Numeric/DateTime) - `yAxis` :
AxisModel— configuration for Y axis (Labels/Numeric/DateTime)
---
Key Methods
- `clearSelection()` — clear selected cells
- `refresh()` — re-render the heatmap
- `destroy()` — teardown component
- `export(type, fileName, orientation)` — export as image/PDF
- `print()` — print the heatmap
---
Important Events
- `cellClick` :
ICellClickEventArgs— user clicked a cell - `cellDoubleClick` :
ICellClickEventArgs— double-click on cell - `cellRender` :
ICellEventArgs— fired while rendering each cell (use to customize) - `cellSelected` :
ISelectedEventArgs— when selection completes - `tooltipRender` :
ITooltipEventArgs— customize tooltip content - `legendRender` :
ILegendRenderEventArgs— fired when legend is rendered - `load` / `loaded` :
ILoadedEventArgs— lifecycle load events - `resized` :
IResizeEventArgs— when heatmap container is resized
---
Models & Event Args (select)
- `CellSettingsModel`
- `PaletteSettingsModel`
- `AxisModel`
- `ICellClickEventArgs`
- `ICellEventArgs`
- `ISelectedEventArgs`
- `ITooltipEventArgs`
For complete and authoritative API anchor links, use the official index above and search for the exact member or event name (the index exposes anchors for models and event-arg interfaces).
````
Axes Configuration
API Reference: references/api-reference.md
Table of Contents
- Axis Types Overview
- Category Axes
- Basic Category Setup
- Categorical with Many Labels
- Numeric Axes
- Basic Numeric Setup
- Numeric Axis with Custom Ranges
- DateTime Axes
- Basic DateTime Setup
- DateTime with Different Intervals
- DateTime Label Formats
- Axis Customization
- Axis Titles and Labels
- Axis Intervals and Ranges
- Axis Label Styling
- Inverted and Opposed Axes
- Inverted Axes
- Opposed Axes
- Axis Edge Cases
- Missing Data Points
- Very Long Labels
- High-Cardinality Axes
Axis Types Overview
HeatMap supports three axis types to handle different data scenarios:
| Axis Type | Use Case | Example Data |
|---|---|---|
| Category | Categorical, text labels | Products, regions, quarters |
| Numeric | Numeric indices | Row/column numbers |
| DateTime | Time-based data | Dates, times, months |
Category Axes
Use Labels type for product names, regions, quarters, or Object text categories.
Basic Category Setup
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, LegendService, TooltipService, AdaptorService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [LegendService, TooltipService, AdaptorService],
template: `
<ejs-heatmap
id='container'
style="display:block;"
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'>
</ejs-heatmap>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
// 12 Outer Arrays (X-Axis) x 6 Inner Values (Y-Axis)
public dataSource: number[][] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68],
[99, 28, 22, 4, 66, 90],
[14, 26, 97, 69, 69, 3],
[7, 46, 47, 47, 88, 6],
[41, 55, 73, 23, 3, 79],
[56, 69, 21, 86, 3, 33],
[45, 7, 53, 81, 95, 79],
[60, 77, 74, 68, 88, 51],
[25, 25, 10, 12, 78, 14],
[25, 56, 55, 58, 12, 82],
[74, 33, 88, 23, 86, 59]
];
public xAxis: Object = {
valueType: 'Category',
// Must match the 12 rows of the outer array
labels: ['Nancy', 'Andrew', 'Janet', 'Margaret', 'Steven', 'Michael',
'Robert', 'Laura', 'Anne', 'Paul', 'Karin', 'Mario'],
};
public yAxis: Object = {
valueType: 'Category',
// Must match the 6 columns of the inner array
labels: ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'],
};
}Categorical with Many Labels
xAxis: Object = {
valueType: "Category",
labels: [
'Product A', 'Product B', 'Product C', 'Product D',
'Product E', 'Product F', 'Product G', 'Product H'
]
};Numeric Axes
Use Numeric type for numeric indices and ranges.
Basic Numeric Setup
import { Component, ViewEncapsulation } from '@angular/core';
import {
HeatMapModule,
LegendService,
TooltipService,
AdaptorService
} from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [LegendService, TooltipService, AdaptorService],
template: `
<ejs-heatmap
id='container'
style="display:block;"
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'>
</ejs-heatmap>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
// 12 rows (X-Axis: 0-11) x 6 columns (Y-Axis: 0-5)
public dataSource: number[][] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68],
[99, 28, 22, 4, 66, 90],
[14, 26, 97, 69, 69, 3],
[7, 46, 47, 47, 88, 6],
[41, 55, 73, 23, 3, 79],
[56, 69, 21, 86, 3, 33],
[45, 7, 53, 81, 95, 79],
[60, 77, 74, 68, 88, 51],
[25, 25, 10, 12, 78, 14],
[25, 56, 55, 58, 12, 82],
[74, 33, 88, 23, 86, 59]
];
public xAxis: Object = {
valueType: "Numeric",
minimum: 0,
maximum: 11,
increment: 1
};
public yAxis: Object = {
valueType: "Numeric",
minimum: 0,
maximum: 5,
increment: 1
};
}Numeric Axis with Custom Ranges
xAxis: Object = {
valueType: 'Numeric',
minimum: 2020,
maximum: 2025,
interval: 1,
labels: ['2020', '2021', '2022', '2023', '2024', '2025']
};DateTime Axes
Use DateTime type for time-series data and temporal analysis.
Basic DateTime Setup
import { Component, ViewEncapsulation } from '@angular/core';
import {
HeatMapModule,
LegendService,
TooltipService,
AdaptorService
} from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [LegendService, TooltipService, AdaptorService],
template: `
<ejs-heatmap
id='container'
style="display:block;"
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[titleSettings]='titleSettings'
[legendSettings]='legendSettings'
[cellSettings]='cellSettings'>
</ejs-heatmap>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
// 11 Rows (Years 2007-2017) x 12 Columns (Months Jan-Dec)
public dataSource: number[][] = [
[36371, 25675, 28292, 33399, 35980, 38585, 39351, 39964, 36543, 30529, 33298, 36985],
[34702, 27618, 31063, 34525, 36772, 35410, 38750, 39467, 35390, 34196, 35302, 35703],
[34522, 31324, 32128, 34231, 36817, 34381, 37180, 38255, 32776, 32645, 31539, 32981],
[32213, 28755, 29517, 31214, 33747, 33507, 35763, 36837, 32910, 33437, 30659, 31965],
[31282, 28663, 32952, 33941, 34506, 36875, 38836, 35497, 34285, 34094, 32256, 33699],
[31714, 29405, 33745, 32838, 33461, 35034, 36122, 37943, 34128, 30624, 32398, 33522],
[32064, 28387, 33751, 32537, 34034, 35977, 37196, 38301, 33627, 34115, 31072, 33939],
[32417, 27868, 30807, 33386, 35284, 36126, 39753, 40978, 35777, 35277, 31281, 35411],
[32494, 29848, 34385, 35804, 37943, 38722, 41315, 41335, 37177, 37443, 32457, 37304],
[34378, 29576, 30547, 35664, 36622, 38145, 40347, 41868, 38252, 36505, 29576, 36450],
[35219, 31670, 32589, 34927, 36998, 39825, 41126, 42002, 37021, 36583, 32408, 37108]
];
public titleSettings: Object = {
text: 'Monthly Flight Traffic at JFK Airport',
textStyle: {
size: '15px',
fontWeight: '500',
fontFamily: 'Segoe UI'
}
};
public xAxis: Object = {
valueType: "DateTime",
minimum: new Date(2007, 0, 1),
maximum: new Date(2017, 0, 1),
intervalType: "Years",
labelFormat: "yyyy",
labelRotation: 45
};
public yAxis: Object = {
valueType: 'Category',
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'July', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec']
};
public legendSettings: Object = {
visible: false
};
public cellSettings: Object = {
showLabel: false,
border: { width: 0 },
format: '{value} flights'
};
}DateTime with Different Intervals
// Daily data
xAxis: Object = {
valueType: "DateTime",
intervalType: 'Days',
interval: 1,
labelFormat: 'MMM dd'
};
// Monthly data
xAxis: Object = {
valueType: "DateTime",
intervalType: 'Months',
interval: 1,
labelFormat: 'MMM yyyy'
};
// Quarterly data
xAxis: Object = {
valueType: "DateTime",
intervalType: 'Quarters',
interval: 1,
labelFormat: 'Q# yyyy'
};
// Hourly data
xAxis: Object = {
valueType: "DateTime",
intervalType: 'Hours',
interval: 6, // Every 6 hours
labelFormat: 'HH:mm'
};DateTime Label Formats
// Common date format patterns
labelFormat: 'MMM dd' // "Jan 01", "Feb 15"
labelFormat: 'dd/MM/yyyy' // "01/01/2024"
labelFormat: 'yyyy-MM-dd' // "2024-01-01"
labelFormat: 'HH:mm' // "14:30", "09:15"
labelFormat: 'd MMM' // "1 Jan", "15 Feb"
labelFormat: 'ddd' // "Mon", "Tue", "Wed"Axis Customization
Axis Titles and Labels
xAxis: Object = {
valueType: "Category",
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
title: { text: 'Months' },
labelRotation: 45, // Rotate labels by 45 degrees
labelIntersectAction: 'Trim' // Trim long labels
};
yAxis: Object = {
valueType: "Category",
labels: ['Region A', 'Region B', 'Region C'],
title: { text: 'Sales Regions' }
};Axis Intervals and Ranges
// Numeric axis with custom intervals
xAxis: Object = {
valueType: 'Numeric',
minimum: 0,
maximum: 100,
interval: 20, // Show 0, 20, 40, 60, 80, 100
majorGridLines: { width: 0 }
};
// DateTime axis with interval control
xAxis: Object = {
valueType: "DateTime",
intervalType: 'Days',
interval: 7, // Show every 7 days
labelFormat: 'MMM dd'
};Axis Label Styling
xAxis: Object = {
valueType: "Category",
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
textStyle: {
color: '#4472C4',
size: '14px',
fontFamily: 'Segoe UI'
},
title: {
text: 'Quarters',
textStyle: {
color: '#333',
size: '16px',
bold: true
}
}
};Inverted and Opposed Axes
Inverted Axes
Flip axis direction to show data in reverse order.
import { Component, ViewEncapsulation } from '@angular/core';
import {
HeatMapModule,
LegendService,
TooltipService,
AdaptorService
} from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [LegendService, TooltipService, AdaptorService],
template: `
<ejs-heatmap
id='container'
style="display:block;"
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[titleSettings]='titleSettings'
[legendSettings]='legendSettings'
[cellSettings]='cellSettings'>
</ejs-heatmap>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
// 11 Year Rows (X-Axis) x 12 Month Columns (Y-Axis)
public dataSource: number[][] = [
[36371, 25675, 28292, 33399, 35980, 38585, 39351, 39964, 36543, 30529, 33298, 36985],
[34702, 27618, 31063, 34525, 36772, 35410, 38750, 39467, 35390, 34196, 35302, 35703],
[34522, 31324, 32128, 34231, 36817, 34381, 37180, 38255, 32776, 32645, 31539, 32981],
[32213, 28755, 29517, 31214, 33747, 33507, 35763, 36837, 32910, 33437, 30659, 31965],
[31282, 28663, 32952, 33941, 34506, 36875, 38836, 35497, 34285, 34094, 32256, 33699],
[31714, 29405, 33745, 32838, 33461, 35034, 36122, 37943, 34128, 30624, 32398, 33522],
[32064, 28387, 33751, 32537, 34034, 35977, 37196, 38301, 33627, 34115, 31072, 33939],
[32417, 27868, 30807, 33386, 35284, 36126, 39753, 40978, 35777, 35277, 31281, 35411],
[32494, 29848, 34385, 35804, 37943, 38722, 41315, 41335, 37177, 37443, 32457, 37304],
[34378, 29576, 30547, 35664, 36622, 38145, 40347, 41868, 38252, 36505, 29576, 36450],
[35219, 31670, 32589, 34927, 36998, 39825, 41126, 42002, 37021, 36583, 32408, 37108]
];
public titleSettings: Object = {
text: 'Monthly Flight Traffic at JFK Airport',
textStyle: {
size: '15px',
fontWeight: '500',
fontFamily: 'Segoe UI'
}
};
public xAxis: Object = {
valueType: "DateTime",
minimum: new Date(2007, 0, 1),
maximum: new Date(2017, 0, 1),
intervalType: "Years",
labelFormat: "yyyy",
labelRotation: 45,
isInversed: true // Flips the axis from Right-to-Left
};
public yAxis: Object = {
valueType: 'Category',
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'July', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec']
};
public legendSettings: Object = {
visible: false
};
public cellSettings: Object = {
showLabel: false,
border: { width: 0 },
format: '{value} flights'
};
}When to use:
- Right-to-left layouts or RTL languages
- Bottom-to-top progression preferred
- Data organization requires reversal
Opposed Axes
Position axes on opposite sides (unusual but supported).
xAxis: Object = {
valueType: "Category",
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
opposedPosition: true // X-axis at top
};
yAxis: Object = {
valueType: "Category",
labels: ['North', 'South', 'East'],
opposedPosition: true // Y-axis at right
};When to use:
- Multiple heatmaps side-by-side
- Special layout requirements
- Custom UI arrangements
Axis Edge Cases
Missing Data Points
If your data doesn't have values for all axis combinations:
dataSource: Object[] = [
{ Product: 'A', Quarter: 'Q1', Sales: 100 },
{ Product: 'A', Quarter: 'Q2', Sales: 120 },
// Q3 and Q4 for Product A missing - cells will be empty
{ Product: 'B', Quarter: 'Q1', Sales: 90 },
{ Product: 'B', Quarter: 'Q2', Sales: 110 }
];Solution: Ensure complete grid or use valueBound for color mapping.
Very Long Labels
Handle long axis labels:
xAxis: Object = {
valueType: "Category",
labels: ['Very Long Product Name 1', 'Very Long Product Name 2'],
labelRotation: 45,
labelIntersectAction: 'Trim',
labelStyle: { size: '12px' }
};High-Cardinality Axes
For many unique categories:
// 100+ products - consider aggregation instead
// Or use numeric axis with categorical legend
yAxis: Object = {
valueType: 'Numeric',
minimum: 0,
maximum: 99,
interval: 10,
labels: [...productNames] // Explicitly map numbers to products
};Data Binding & Formats
API Reference: references/api-reference.md
Table of Contents
- Data Binding Overview
- JSON Array Format
- Basic Structure
- Complete Example: Sales Data
- Field Mapping in HeatMap
- 2D Array Format
- Basic Structure
- Complete Example: Numeric Matrix
- When to Use 2D Arrays
- DataManager Integration
- Basic DataManager Setup
- API Response Format
- Live Data Updates
- Update Entire DataSource
- Real-time Polling Pattern
- Binding Best Practices
- Do
- Don't
- Performance Tips
Data Binding Overview
HeatMap supports multiple data formats to handle different scenarios:
| Format | Use Case | When to Use |
|---|---|---|
| JSON Array | Structured labeled data | Most common, explicit dimensions |
| 2D Array | Matrix/grid data | Numeric grids, numerical indices |
| DataManager | Remote/API data | Server-side filtering, large datasets |
JSON Array Format
The most common format using objects with xName, yName, and value fields.
Basic Structure
dataSource: Object[] = [
{ xAxis: 'label1', yAxis: 'label1', value: 10 },
{ xAxis: 'label1', yAxis: 'label2', value: 15 },
{ xAxis: 'label2', yAxis: 'label1', value: 20 },
{ xAxis: 'label2', yAxis: 'label2', value: 25 }
];Complete Example: Sales Data
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, LegendService, TooltipService, AdaptorService } from '@syncfusion/ej2-angular-heatmap';
@Component({
imports: [HeatMapModule],
providers: [LegendService, TooltipService, AdaptorService],
standalone: true,
selector: 'my-app',
template: `
<ejs-heatmap id='container' style="display:block;"
[dataSource]='dataSource'
[dataSourceSettings]='dataSourceSettings'
[xAxis]='xAxis'
[yAxis]='yAxis'
[cellSettings]='cellSettings'
[titleSettings]='titleSettings'
[paletteSettings]='paletteSettings'>
</ejs-heatmap>`
})
export class AppComponent {
titleSettings: Object = {
text: 'Annual Sales Revenue by Product Category',
textStyle: {
size: '15px',
fontWeight: '500',
fontFamily: 'Segoe UI'
}
};
// X-Axis represents the Categories (Regions or Product Groups)
xAxis: Object = {
labels: ['Electronics', 'Fashion', 'Home & Garden', 'Sports', 'Toys'],
labelRotation: 45,
labelIntersectAction: 'None',
};
// Y-Axis represents the Sales Years
yAxis: Object = {
title: { text: 'Fiscal Year' },
labels: ['2019', '2020', '2021', '2022', '2023'],
};
// Updated Sales Data Source (Table Format)
dataSource: Object[] = [
{ 'Category': 'Electronics', '2019': 850, '2020': 920, '2021': 1100, '2022': 1050, '2023': 1300 },
{ 'Category': 'Fashion', '2019': 420, '2020': 380, '2021': 450, '2022': 510, '2023': 580 },
{ 'Category': 'Home & Garden', '2019': 300, '2020': 450, '2021': 500, '2022': 480, '2023': 520 },
{ 'Category': 'Sports', '2019': 150, '2020': 200, '2021': 320, '2022': 340, '2023': 410 },
{ 'Category': 'Toys', '2019': 220, '2020': 250, '2021': 280, '2022': 300, '2023': 350 }
];
dataSourceSettings: Object = {
isJsonData: true,
adaptorType: 'Table',
xDataMapping: 'Category', // Maps the 'Category' field to the X-Axis
};
paletteSettings: Object = {
palette: [
{ color: '#E5E7EB', label: 'Low Sales' }, // Light Grey
{ color: '#3B82F6', label: 'High Sales' } // Blue
],
};
cellSettings: Object = {
showLabel: true,
format: '${value}k', // Shows value as $850k
border: {
width: 1,
radius: 4,
color: 'white'
}
};
}Field Mapping in HeatMap
<ejs-heatmap [dataSource]='dataSource'
[xAxis]='{ valueType: "Category", labels: ["Q1", "Q2", "Q3", "Q4"] }'
[yAxis]='{ valueType: "Category", labels: ["Product A", "Product B", "Product C"] }'
[cellSettings]='{ showLabel: true }'>
</ejs-heatmap>How it works: 1. HeatMap iterates through dataSource array 2. Groups by xAxis values (Quarter) 3. Groups by yAxis values (Product) 4. Uses value field for cell color intensity
2D Array Format
Use 2D arrays for pure numeric grids or when data is already matrix-shaped.
Basic Structure
dataSource: Object[] = [
[10, 15, 20], // Row 1: [row1-col1, row1-col2, row1-col3]
[20, 25, 30], // Row 2: [row2-col1, row2-col2, row2-col3]
[30, 35, 40] // Row 3: [row3-col1, row3-col2, row3-col3]
];Complete Example: Numeric Matrix
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, LegendService, TooltipService, AdaptorService } from '@syncfusion/ej2-angular-heatmap';
@Component({
imports: [HeatMapModule],
providers: [LegendService, TooltipService, AdaptorService],
standalone: true,
selector: 'my-app',
template: `
<ejs-heatmap id='heatmap'
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'>
</ejs-heatmap>`
})
export class AppComponent {
// 2D array: 5x5 correlation matrix
dataSource: Object[] = [
[1.0, 0.8, 0.6, 0.4, 0.2], // Variable 1
[0.8, 1.0, 0.7, 0.5, 0.3], // Variable 2
[0.6, 0.7, 1.0, 0.6, 0.4], // Variable 3
[0.4, 0.5, 0.6, 1.0, 0.7], // Variable 4
[0.2, 0.3, 0.4, 0.7, 1.0] // Variable 5
];
xAxis: Object = {
labels: ['Var1', 'Var2', 'Var3', 'Var4', 'Var5'],
valueType: 'Category'
};
yAxis: Object = {
labels: ['Var1', 'Var2', 'Var3', 'Var4', 'Var5'],
valueType: 'Category'
};
}When to Use 2D Arrays
- Correlation matrices: All-vs-all comparisons
- Heatmap grids: Simple numeric data without complex labels
- Performance: Slightly faster for very large matrices
- Data transformation: When reshaping existing matrix data
DataManager Integration
Bind HeatMap to remote data using DataManager for server-side operations.
Basic DataManager Setup
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule } from '@syncfusion/ej2-angular-heatmap';
import { DataManager, WebApiAdaptor } from '@syncfusion/ej2-data';
@Component({
imports: [HeatMapModule],
standalone: true,
selector: 'app-remote-heatmap',
template: `
<ejs-heatmap id='heatmap'
[dataSource]='dataManager'
[xAxis]='xAxis'
[yAxis]='yAxis'>
</ejs-heatmap>
`,
encapsulation: ViewEncapsulation.None
})
export class RemoteHeatMapComponent {
dataManager: Object;
ngOnInit() {
// Connect to your API endpoint
this.dataManager = new DataManager({
url: 'https://api.example.com/heatmap-data',
adaptor: new WebApiAdaptor(),
crossDomain: true
});
}
xAxis: Object = { valueType: 'Category', labels: ['Q1', 'Q2', 'Q3', 'Q4'] };
yAxis: Object = { valueType: 'Category', labels: ['Product A', 'Product B'] };
}API Response Format
Expected server response (JSON array):
[
{ "Quarter": "Q1", "Product": "Product A", "Sales": 45000 },
{ "Quarter": "Q1", "Product": "Product B", "Sales": 38000 },
{ "Quarter": "Q2", "Product": "Product A", "Sales": 52000 },
{ "Quarter": "Q2", "Product": "Product B", "Sales": 41000 }
]Live Data Updates
Dynamically update heatmap data when new data arrives.
Update Entire DataSource
export class DynamicHeatMapComponent {
@ViewChild('heatmap') heatmapObj: HeatMapComponent;
dataSource: Object[] = [];
ngAfterViewInit() {
// Update with new data after 2 seconds
setTimeout(() => {
this.dataSource = [
{ Q: 'Q1', P: 'A', V: 100 },
{ Q: 'Q1', P: 'B', V: 150 },
{ Q: 'Q2', P: 'A', V: 120 },
{ Q: 'Q2', P: 'B', V: 170 }
];
// Refresh heatmap
this.heatmapObj.refresh();
}, 2000);
}
}Real-time Polling Pattern
export class RealtimeHeatMapComponent {
@ViewChild('heatmap') heatmapObj: HeatMapComponent;
dataSource: Object[] = [];
pollInterval: Object;
ngOnInit() {
this.startPolling();
}
startPolling() {
this.pollInterval = setInterval(() => {
this.fetchLatestData();
}, 5000); // Poll every 5 seconds
}
fetchLatestData() {
// Fetch from API
this.http.get('api/heatmap-data').subscribe(data => {
this.dataSource = data;
this.heatmapObj.refresh();
});
}
ngOnDestroy() {
clearInterval(this.pollInterval);
}
}Binding Best Practices
Do
- Use JSON format for labeled data: Most readable and maintainable
- Provide complete datasets: Don't bind partial data expecting rendering
- Validate data before binding: Check for nulls, undefined values
- Use DataManager for large datasets: Better performance and memory efficiency
Don't
- Don't mix data formats: Use consistent JSON or 2D arrays, not both
- Don't bind data inline in template: Move to component class for clarity
- Don't update partial cells: Update entire dataSource and call refresh()
- Don't assume axis labels match data: Explicitly define xAxis/yAxis labels
Performance Tips
1. Large Datasets (>10k cells):
- Canvas rendering automatically switches on (check
renderingMode) - Consider server-side aggregation
- Use DataManager with paging
2. Frequent Updates:
- Batch updates into single refresh call
- Use reactive data patterns (RxJS Observables)
3. Memory Optimization:
- Limit time-series window (e.g., last 30 days)
- Implement data aggregation on server
Getting Started with Angular HeatMap
API Reference: references/api-reference.md
Table of Contents
- When to Use This Skill
- Installation
- Module Setup
- Option 1: Standalone Component (Angular 14+, Recommended)
- Option 2: NgModule (Traditional, Backward Compatible)
- Create Your First HeatMap
- Minimal Example
- In Your HTML Template
- Add Styling
- Verify Setup
- Check if HeatMap Renders
- Common Setup Issues
When to Use This Skill
Use this skill when you need to:
- Set up Angular HeatMap — Install and configure Syncfusion HeatMap in Angular projects
- Install packages — Add required npm packages
- Configure modules — Import HeatMapModule in Angular modules
- Data Matrix Visualization: Display 2D data arrays with color-coded cells
- Correlation Analysis: Visualize relationships between multiple variables
- Time-Series Heatmaps: Show patterns over time (e.g., hourly/daily activity)
- Category Comparison: Compare performance across categories and metrics
- Intensity Mapping: Display heatmaps with gradient colors representing value intensity
- Interactive Selection: Enable user selection of cells with tooltips and event handling
- Accessibility Requirements: Implement WCAG-compliant heatmaps with ARIA support
- Custom Styling: Apply themes, palettes, and custom rendering (SVG/Canvas)
- Bubble Heatmaps: Visualize data as bubbles with size and color encoding
- Large Datasets: Handle auto-switching between SVG and Canvas rendering modes
Installation
Install Syncfusion Angular HeatMap component via npm:
npm install @syncfusion/ej2-angular-heatmapModule Setup
Option 1: Standalone Component (Angular 14+, Recommended)
For modern standalone components, import HeatMapModule directly:
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule } from '@syncfusion/ej2-angular-heatmap';
@Component({
imports: [HeatMapModule], // Import module here
standalone: true,
selector: 'app-heatmap',
template: `<ejs-heatmap id='heatmap'></ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class HeatMapComponent {
}Advantages:
- No module file needed
- Tree-shakeable imports
- Cleaner component definition
- Recommended for new projects
Option 2: NgModule (Traditional, Backward Compatible)
For traditional module-based components, register in app.module.ts:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HeatMapModule } from '@syncfusion/ej2-angular-heatmap';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, HeatMapModule], // Import module
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }Use when:
- Migrating legacy applications
- Organization standardizes on NgModule approach
- Complex feature modules required
Create Your First HeatMap
Minimal Example
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule } from '@syncfusion/ej2-angular-heatmap';
@Component({
imports: [HeatMapModule],
standalone: true,
selector: 'my-app',
template: `
<ejs-heatmap id='heatmap-container'
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[cellSettings]='cellSettings'>
</ejs-heatmap>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
/**
* 2D Array Format:
* Row 1 (Milk): [2005, 2006, 2007]
* Row 2 (Bread): [2005, 2006, 2007]
* Row 3 (Butter): [2005, 2006, 2007]
*/
dataSource: number[][] = [
[21, 22, 23], // Sales for Milk
[18, 19, 20], // Sales for Bread
[15, 16, 17] // Sales for Butter
];
xAxis: Object = {
labels: ['2005', '2006', '2007'],
valueType: 'Category'
};
yAxis: Object = {
labels: ['Milk', 'Bread', 'Butter'],
valueType: 'Category'
};
cellSettings: Object = {
showLabel: true,
format: '{value}' // Displays the sales number inside the cell
};
}In Your HTML Template
If using standalone component in template:
<!-- app.component.html -->
<div class="container">
<h1>Sales HeatMap</h1>
<my-ap></my-ap>
</div>Add Styling
Optional CSS for heatmap container:
/* styles.css */
#heatmap-container {
width: 100%;
height: 400px;
margin-top: 20px;
}Verify Setup
Check if HeatMap Renders
1. Run development server:
ng serve2. Open browser:
- Navigate to
http://localhost:4200 - Look for a grid visualization with colored cells
- Each cell represents a Sales value
- Colors indicate value intensity (darker = higher)
3. Troubleshoot if not rendering:
Problem: "Cannot find module '@syncfusion/ej2-angular-heatmap'"
- Solution: Run
npm installagain and check package.json
Problem: Module not imported
- Solution: Verify
HeatMapModulein component'simportsarray
Problem: Component selector not found
- Solution: Ensure selector name (
app-heatmap) matches in HTML
Problem: No styling applied
- Solution: Add
encapsulation: ViewEncapsulation.Noneto component
Common Setup Issues
Issue: TypeScript compilation errors
- Ensure
@angular/coreis also installed:npm install @angular/core - Check Angular version compatibility
Issue: HeatMap appears but no data
- Verify
dataSourcearray is not empty - Check
xAxisandyAxislabels match your data
Issue: Module errors on import
- Clear node_modules:
rm -r node_modules && npm install - Check package version in package.json
Interactivity, Events & Accessibility
API Reference: references/api-reference.md
Table of Contents
- Cell Selection
- Enable Selection
- Selection Types
- Tooltips and Data Labels
- Enable Tooltips
- Custom Tooltip Template
- Tooltip Appearance
- Cell Events
- Cell Click Event
- Multiple Event Handling
- Data Label Formatting
- Basic Data Labels
- Custom Label Formatting
- Label Styling
- WCAG Accessibility
- Basic Accessibility Setup
- WCAG Level AA Checklist
- Screen Reader Support
- ARIA Attributes
- Accessible Data Table Alternative
- Best Practices
- Do
- Dont
Cell Selection
Enable users to select and interact with heatmap cells.
Enable Selection
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule } from '@syncfusion/ej2-angular-heatmap';
import { ISelectedEventArgs } from '@syncfusion/ej2-heatmap';
@Component({
imports: [HeatMapModule],
standalone: true,
selector: 'my-app',
template: `
<div>
<p>Selected Cell: {{ selectedCell }}</p>
<ejs-heatmap #heatmap id='heatmap'
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[allowSelection]='true'
[cellSettings]='cellSettings'
(cellSelected)='onCellSelect($event)'>
</ejs-heatmap>
</div>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
/**
* 2D Datasource:
* Row 1 (A): [Q1, Q2]
* Row 2 (B): [Q1, Q2]
*/
dataSource: number[][] = [
[10, 15], // Product A values for Q1 and Q2
[20, 25] // Product B values for Q1 and Q2
];
xAxis: Object = {
valueType: 'Category',
labels: ['Q1', 'Q2']
};
yAxis: Object = {
valueType: 'Category',
labels: ['A', 'B']
};
cellSettings: Object = {
showLabel: true
};
selectedCell: string = 'None';
onCellSelect(args: ISelectedEventArgs) {
console.log(args.data[0].value);
// When using 2D arrays, event.xValue and event.yValue return the label names
this.selectedCell = args.data[0].value.toString();
//console.log('Cell selected:', event);
}
}Selection Types
// Single cell selection
allowSelection: true // Default
// Multiple cell selection
enableMultiSelect : true
// Range selection (not directly supported, use events for custom logic)Tooltips and Data Labels
Display detailed information on hover and within cells.
Enable Tooltips
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, TooltipService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [TooltipService],
template: `
<ejs-heatmap id='container' style="display:block;"
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[titleSettings]='titleSettings'
[cellSettings]='cellSettings'
[showTooltip]='showTooltip'>
</ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
// X-Axis: 8 Countries
public xAxis: Object = {
labels: ['Canada', 'China', 'Egypt', 'Mexico', 'Norway', 'Russia', 'UK', 'USA'],
valueType: 'Category'
};
// Y-Axis: 10 Years
public yAxis: Object = {
labels: ['2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009'],
valueType: 'Category'
};
/**
* 2D Array DataSource:
* Each inner array represents one Year (Y-Axis)
* Each value in that array represents a Country (X-Axis)
*/
public dataSource: number[][] = [
[0.72, 2.28, 2.02, 3.21, 3.22, 3.30, 5.80, 6.91], // 2000
[0.71, 2.29, 2.17, 3.26, 3.13, 3.39, 5.74, 7.40], // 2001
[0.71, 2.09, 2.30, 3.45, 3.04, 3.40, 5.64, 8.13], // 2002
[0.67, 1.84, 2.39, 3.47, 2.95, 3.48, 5.44, 8.80], // 2003
[0.72, 1.64, 2.36, 3.42, 2.69, 3.60, 5.18, 9.04], // 2004
[0.53, 1.49, 2.52, 3.34, 2.49, 3.67, 5.08, 9.24], // 2005
[0.53, 1.49, 2.62, 3.14, 2.27, 3.73, 5.07, 9.43], // 2006
[0.56, 1.39, 2.57, 2.83, 2.18, 3.79, 5.00, 9.35], // 2007
[0.58, 1.32, 2.57, 2.64, 2.06, 3.79, 5.35, 9.49], // 2008
[0.56, 1.23, 2.74, 2.61, 1.87, 4.07, 5.47, 9.69] // 2009
];
public titleSettings: Object = {
text: 'Crude Oil Production of Non-OPEC Countries (Million barrels per day)',
textStyle: {
size: '15px',
fontWeight: '500',
fontFamily: 'Segoe UI'
}
};
public cellSettings: Object = {
showLabel: false,
};
public showTooltip: boolean = true;
}Custom Tooltip Template
tooltipSettings: Object = {
enable: true,
template: `
<div>
Tooltip Template
</div>
`
};Tooltip Appearance
tooltipSettings: Object = {
border: {
color: '#333',
width: 1
},
fill: '#FFF',
textStyle: {
color: '#000',
size: '12px'
},
};Cell Events
Handle various cell interaction events.
Cell Click Event
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, TooltipService } from '@syncfusion/ej2-angular-heatmap';
import { ICellClickEventArgs } from '@syncfusion/ej2-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [TooltipService], // SelectionService removed
template: `
<ejs-heatmap id='heatmap'
[dataSource]='dataSource'
(cellClick)='onCellClick($event)'>
</ejs-heatmap>
<p>Status: {{ status }}</p>
`,
})
export class AppComponent {
public dataSource: number[][] = [[10, 15], [18, 20]];
public status: string = 'Ready';
// Triggered immediately when a cell is clicked
public onCellClick(args: ICellClickEventArgs): void {
// ICellClickEventArgs provides the value, xLabel, and yLabel directly
this.status = `Clicked Value: ${args.value} (Cell: ${args.xLabel}, ${args.yLabel})`;
}
}Multiple Event Handling
import { Component, ViewEncapsulation } from '@angular/core';
import {
HeatMapModule,
TooltipService
} from '@syncfusion/ej2-angular-heatmap';
import {
ISelectedEventArgs,
ITooltipEventArgs,
} from '@syncfusion/ej2-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [TooltipService],
template: `
<div>
<p style="font-family: 'Segoe UI'; font-weight: 500;">Status: {{ status }}</p>
<ejs-heatmap id='heatmap'
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[allowSelection]='true'
[showTooltip]='true'
(cellSelected)='onCellSelect($event)'
(cellRender)='onCellRender($event)'>
</ejs-heatmap>
</div>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
// 2D Datasource for Product A and B across Q1 and Q2
public dataSource: number[][] = [
[10, 15], // Product A
[18, 20] // Product B
];
public xAxis: Object = {
labels: ['Q1', 'Q2'],
valueType: 'Category'
};
public yAxis: Object = {
labels: ['A', 'B'],
valueType: 'Category'
};
public status: string = 'Ready';
// Updates the status string when a cell is clicked
public onCellSelect(args: ISelectedEventArgs): void {
if (args.data && args.data.length > 0) {
this.status = `Selected Value: ${args.data[0].value}`;
}
}
// Formats the display text (e.g., dividing value by 2 and adding currency)
public onCellRender(args: any): void {
if (args.value !== null) {
args.displayText = '$ ' + (args.value / 2) + 'K';
}
}
}Data Label Formatting
Display and format values within heatmap cells.
Basic Data Labels
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { HeatMapModule} from '@syncfusion/ej2-angular-heatmap'
import { TooltipService} from '@syncfusion/ej2-angular-heatmap'
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
imports: [ HeatMapModule ],
providers: [TooltipService],
standalone: true,
selector: 'my-app',
template:
`<ejs-heatmap id='container' style="display:block;" [dataSource]='dataSource' [xAxis]='xAxis' [yAxis]='yAxis'
[titleSettings]='titleSettings' [cellSettings]='cellSettings'>
</ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent{
dataSource: Object[] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68],
[99, 28, 22, 4, 66, 90],
[14, 26, 97, 69, 69, 3],
[7, 46, 47, 47, 88, 6],
[41, 55, 73, 23, 3, 79],
[56, 69, 21, 86, 3, 33],
[45, 7, 53, 81, 95, 79],
[60, 77, 74, 68, 88, 51],
[25, 25, 10, 12, 78, 14],
[25, 56, 55, 58, 12, 82],
[74, 33, 88, 23, 86, 59]];
titleSettings: Object = {
text: 'Sales Revenue per Employee (in 1000 US$)',
textStyle: {
size: '15px',
fontWeight: '500',
fontStyle: 'Normal',
fontFamily: 'Segoe UI'
}
};
xAxis: Object = {
labels: ['Nancy', 'Andrew', 'Janet', 'Margaret', 'Steven',
'Michael', 'Robert', 'Laura', 'Anne', 'Paul', 'Karin', 'Mario'],
};
yAxis: Object = {
labels: ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'],
};
cellSettings: Object = {
format: '{value} K'
};
}Custom Label Formatting
// Show as thousands
cellSettings: Object = {
showLabel: true,
format: '${value/1000}k'
};
// Show as percentage
cellSettings: Object = {
showLabel: true,
format: '${(value/100).toFixed(1)}%'
};
// Custom calculation
cellSettings: Object = {
showLabel: true,
format: '${value > 20000 ? "High" : "Low"}'
};Label Styling
cellSettings: Object = {
showLabel: true,
format: '${value}',
textStyle: {
color: '#FFFFFF',
size: '14px',
fontFamily: 'Segoe UI',
bold: true
},
border: {
color: '#333',
width: 1
}
};WCAG Accessibility
Ensure heatmaps meet accessibility standards for all users.
Basic Accessibility Setup
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, TooltipService, LegendService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [TooltipService, LegendService],
template: `
<div role='figure' [attr.aria-label]='accessibilityLabel'>
<h2>Sales Performance Heatmap</h2>
<ejs-heatmap id='heatmap'
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[cellSettings]='cellSettings'
[legendSettings]='legendSettings'>
</ejs-heatmap>
<p id='heatmap-description' class='sr-only' style="display:none;">
This heatmap displays sales revenue by product and quarter.
Lighter colors = lower revenue, darker colors = higher revenue.
</p>
</div>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
/**
* 2D Datasource:
* Rows represent Product A and Product B
* Columns represent Q1 and Q2
*/
public dataSource: number[][] = [
[45000, 52000], // Product A: Q1, Q2
[38000, 41000] // Product B: Q1, Q2
];
public xAxis: Object = {
labels: ['Q1', 'Q2'],
valueType: 'Category'
};
public yAxis: Object = {
labels: ['Product A', 'Product B'],
valueType: 'Category'
};
public accessibilityLabel = 'Heatmap showing sales revenue by product and quarter. Values range from $38,000 to $52,000.';
public cellSettings: Object = {
showLabel: true,
format: '${value}'
};
public legendSettings: Object = {
visible: true,
position: 'Bottom'
};
}WCAG Level AA Checklist
- ✅ Color Contrast: Ensure text on cell background meets 4.5:1 ratio
- ✅ ARIA Labels: Proper aria-labels and roles
Screen Reader Support
Make heatmaps usable with screen readers.
ARIA Attributes
@Component({
template: `
<div role='figure'
[attr.aria-label]=''Sales Heatmap by Product and Quarter''
[attr.aria-describedby]=''heatmap-description''>
<ejs-heatmap id='heatmap'
[dataSource]='dataSource'
[cellSettings]='cellSettings'
[tooltip]='tooltipSettings'>
</ejs-heatmap>
<div id='heatmap-description' class='sr-only'>
Heatmap showing sales revenue. Rows represent products A, B, C.
Columns represent quarters Q1-Q4. Values range from $10k to $50k.
</div>
</div>
`,
styles: [`
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0,0,0,0);
border: 0;
}
`]
})
export class ScreenReaderComponent {
// ...
}Accessible Data Table Alternative
@Component({
template: `
<div>
<!-- Heatmap for visual users -->
<div [attr.aria-hidden]='true'>
<ejs-heatmap id='heatmap' [dataSource]='dataSource'>
</ejs-heatmap>
</div>
<!-- Data table for screen readers -->
<table class='sr-only' role='region'
[attr.aria-label]=''Sales Data Table''>
<caption>Sales data by product and quarter</caption>
<thead>
<tr>
<th>Product</th>
<th>Q1</th>
<th>Q2</th>
<th>Q3</th>
<th>Q4</th>
</tr>
</thead>
<tbody>
<tr *ngFor='let row of tableData'>
<td>{{ row.product }}</td>
<td *ngFor='let value of row.values'>{{ value }}</td>
</tr>
</tbody>
</table>
</div>
`
})
export class AccessibleAlternativeComponent {
tableData: Object[] = [];
}Best Practices
Do
- Provide tooltips: Essential for detailed value inspection
- Use keyboard navigation: Full tab and arrow key support
- Include ARIA labels: Screen reader users need context
- Ensure color contrast: Text readable on all backgrounds
- Offer alternative: Provide data table for screen readers
- Test with tools: Use aXe, WAVE, NVDA, JAWS
Don't
- Don't rely on hover alone: Keyboard users can't hover
- Don't use poor color contrast: Fails WCAG AA/AAA
- Don't hide important info in tooltips: Make it accessible
- Don't forget focus indicators: Users need to see focused cells
- Don't skip ARIA attributes: Context needed for assistive tech
- Don't use image-only heatmaps: No alternative for screen readers
Legend Rendering
API Reference: references/api-reference.md
Table of Contents
- Legend Basics
- Enable/Disable Legend
- Legend Visibility
- Legend Positioning
- Position Options
- Complete Positioning Example
- Legend Alignment
- Alignment Options
- Legend Appearance
- Size and Borders
- Label Styling
- Complete Styling Example
- Interactive Legend
- Legend Interaction Pattern
- Custom Legend Formatting
- Format Legend Labels
- Legend with Custom Color Mapping
- Legend Events
- Best Practices
- Do
- Don't
Legend Basics
The legend displays the color-to-value mapping for heatmap cells, helping users interpret the visualization.
Enable/Disable Legend
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, LegendService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [LegendService],
template: `
<ejs-heatmap id='container' style="display:block;"
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[titleSettings]='titleSettings'
[paletteSettings]='paletteSettings'
[legendSettings]='legendSettings'
[cellSettings]='cellSettings'>
</ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
// 2D Array Datasource (12 Rows x 6 Columns)
public dataSource: number[][] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68],
[99, 28, 22, 4, 66, 90],
[14, 26, 97, 69, 69, 3],
[7, 46, 47, 47, 88, 6],
[41, 55, 73, 23, 3, 79],
[56, 69, 21, 86, 3, 33],
[45, 7, 53, 81, 95, 79],
[60, 77, 74, 68, 88, 51],
[25, 25, 10, 12, 78, 14],
[25, 56, 55, 58, 12, 82],
[74, 33, 88, 23, 86, 59]
];
public titleSettings: Object = {
text: 'Sales Revenue per Employee (in 1000 US$)',
textStyle: {
size: '15px',
fontWeight: '500',
fontFamily: 'Segoe UI'
}
};
public xAxis: Object = {
labels: ['Nancy', 'Andrew', 'Janet', 'Margaret', 'Steven', 'Michael', 'Robert', 'Laura', 'Anne', 'Paul', 'Karin', 'Mario'],
valueType: 'Category'
};
public yAxis: Object = {
labels: ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'],
valueType: 'Category'
};
public cellSettings: Object = {
showLabel: false,
};
public paletteSettings: Object = {
palette: [
{ value: 0, color: '#C2E7EC' },
{ value: 10, color: '#AEDFE6' },
{ value: 20, color: '#9AD7E0' },
{ value: 30, color: '#72C7D4' },
{ value: 40, color: '#5EBFCE' },
{ value: 50, color: '#4AB7C8' },
{ value: 60, color: '#309DAE' },
{ value: 70, color: '#2B8C9B' },
{ value: 80, color: '#206974' },
{ value: 90, color: '#15464D' },
{ value: 100, color: '#000000' },
],
};
public legendSettings: Object = {
visible: true,
height: '150px',
width: '50px'
};
}Legend Visibility
// Hide legend completely
legendSettings: any = {
visible: false
};
// Show legend (default)
legendSettings: any = {
visible: true
};Legend Positioning
Position the legend relative to the heatmap.
Position Options
// Right side (default)
legendSettings: any = {
position: 'Right',
height: '200px',
width: '40px'
};
// Left side
legendSettings: any = {
position: 'Left',
height: '200px',
width: '40px'
};
// Top
legendSettings: any = {
position: 'Top',
height: '40px',
width: '100%'
};
// Bottom
legendSettings: any = {
position: 'Bottom',
height: '50px',
width: '100%'
};Complete Positioning Example
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, LegendService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [LegendService],
template: `
<ejs-heatmap id='container' style="display:block;"
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[titleSettings]='titleSettings'
[legendSettings]='legendSettings'>
</ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
// 2D Array Datasource
public dataSource: number[][] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68],
[99, 28, 22, 4, 66, 90],
[14, 26, 97, 69, 69, 3],
[7, 46, 47, 47, 88, 6],
[41, 55, 73, 23, 3, 79],
[56, 69, 21, 86, 3, 33],
[45, 7, 53, 81, 95, 79],
[60, 77, 74, 68, 88, 51],
[25, 25, 10, 12, 78, 14],
[25, 56, 55, 58, 12, 82],
[74, 33, 88, 23, 86, 59]
];
public titleSettings: Object = {
text: 'Sales Revenue per Employee (in 1000 US$)',
textStyle: {
size: '15px',
fontWeight: '500',
fontFamily: 'Segoe UI'
}
};
public xAxis: Object = {
labels: ['Nancy', 'Andrew', 'Janet', 'Margaret', 'Steven', 'Michael', 'Robert', 'Laura', 'Anne', 'Paul', 'Karin', 'Mario']
};
public yAxis: Object = {
labels: ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat']
};
public legendSettings: Object = {
position: 'Top',
height: '50px',
width: '100%'
};
}Legend Alignment
Align legend items within the legend container.
Alignment Options
// Horizontal alignment
legendSettings: any = {
position: 'Right',
alignment: 'Center' // or 'Near', 'Far'
};
// For vertical legend (Right/Left positions)
legendSettings: any = {
position: 'Right',
alignment: 'Near' // Align to top
};
legendSettings: any = {
position: 'Right',
alignment: 'Far' // Align to bottom
};
// For horizontal legend (Top/Bottom positions)
legendSettings: any = {
position: 'Bottom',
alignment: 'Near' // Align to left
};
legendSettings: any = {
position: 'Bottom',
alignment: 'Far' // Align to right
};Legend Appearance
Customize the visual appearance of the legend.
Size and Borders
legendSettings: any = {
position: 'Right',
height: '250px', // Legend height
width: '60px', // Legend width
};Label Styling
legendSettings: any = {
labelDisplayType: 'Trim', // 'Trim' or 'WrapByWord'
labelFormat: '${value}', // Custom label format
textStyle: {
size: '12px',
color: '#000',
fontFamily: 'Segoe UI'
}
};Complete Styling Example
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, LegendService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [LegendService],
template: `
<ejs-heatmap id='container'
[dataSource]='dataSource'
[legendSettings]='legendSettings'>
</ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
public dataSource: number[][] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68]
];
// Comprehensive Legend Settings
public legendSettings: Object = {
// Position: 'Top', 'Bottom', 'Left', or 'Right'
position: 'Bottom',
// Alignment: 'Near', 'Center', or 'Far'
alignment: 'Center',
// Physical dimensions (can be pixels or percentage)
height: '100px',
width: '70%',
// Label appearance customization
textStyle: {
size: '14px',
fontWeight: '600',
fontFamily: 'Segoe UI',
color: '#333333',
fontStyle: 'Italic'
},
// Optional: Title for the legend itself
title: {
text: 'Revenue Scale',
textStyle: {
size: '12px',
fontWeight: 'Bold'
}
}
};
}Interactive Legend
Enable users to interact with the legend to filter or highlight data.
Legend Interaction Pattern
import { Component, ViewEncapsulation } from '@angular/core';
import {
HeatMapModule,
TooltipService,
LegendService,
ILoadedEventArgs
} from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [TooltipService, LegendService],
template: `
<div class="control-container">
<div class="button-panel" style="margin-bottom: 20px;">
<button (click)='toggleLegend()'>Toggle Legend</button>
<button (click)='changeLegendPosition()'>Change Position ({{currentPosition}})</button>
</div>
<ejs-heatmap id='heatmap'
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[legendSettings]='legendSettings'
(load)='onLoad($event)'>
</ejs-heatmap>
</div>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
// Stores the instance captured from the load event
private heatmapInstance: any;
public dataSource: number[][] = [
[10000, 18000],
[25000, 32000]
];
public xAxis: Object = { valueType: 'Category', labels: ['Q1', 'Q2'] };
public yAxis: Object = { valueType: 'Category', labels: ['Product A', 'Product B'] };
public legendSettings: any = {
visible: true,
position: 'Right',
height: '200px',
width: '40px'
};
public currentPosition: string = 'Right';
private positions: string[] = ['Right', 'Bottom', 'Left', 'Top'];
private positionIndex: number = 0;
// Capture the instance before the component fully renders
public onLoad(args: ILoadedEventArgs): void {
this.heatmapInstance = args.heatmap;
console.log("Instance captured via load event:", this.heatmapInstance);
}
public toggleLegend(): void {
this.legendSettings.visible = !this.legendSettings.visible;
// Use the captured instance to refresh the UI
if (this.heatmapInstance) {
this.heatmapInstance.refresh();
}
}
public changeLegendPosition(): void {
this.positionIndex = (this.positionIndex + 1) % this.positions.length;
this.currentPosition = this.positions[this.positionIndex];
this.legendSettings.position = this.currentPosition;
if (this.heatmapInstance) {
this.heatmapInstance.refresh();
}
}
}
Custom Legend Formatting
Format Legend Labels
legendSettings: any = {
labelFormat: '${value}%', // Show percentage
};
// Example: Show in thousands
labelFormat: '${value/1000}k' // 50000 → "50k"
labelFormat: '${value.toFixed(0)}' // Format with decimalsLegend with Custom Color Mapping
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, LegendService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [LegendService],
template: `
<ejs-heatmap id='container' style="display:block;"
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[titleSettings]='titleSettings'
[paletteSettings]='paletteSettings'
[legendSettings]='legendSettings'>
</ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
// 2D Array Datasource (12 Rows x 6 Columns)
public dataSource: number[][] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68],
[99, 28, 22, 4, 66, 90],
[14, 26, 97, 69, 69, 3],
[7, 46, 47, 47, 88, 6],
[41, 55, 73, 23, 3, 79],
[56, 69, 21, 86, 3, 33],
[45, 7, 53, 81, 95, 79],
[60, 77, 74, 68, 88, 51],
[25, 25, 10, 12, 78, 14],
[25, 56, 55, 58, 12, 82],
[74, 33, 88, 23, 86, 59]
];
public titleSettings: Object = {
text: 'Sales Revenue per Employee (in 1000 US$)',
textStyle: {
size: '15px',
fontWeight: '500',
fontFamily: 'Segoe UI'
}
};
public xAxis: Object = {
labels: ['Nancy', 'Andrew', 'Janet', 'Margaret', 'Steven', 'Michael', 'Robert', 'Laura', 'Anne', 'Paul', 'Karin', 'Mario'],
valueType: 'Category'
};
public yAxis: Object = {
labels: ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'],
valueType: 'Category'
};
public paletteSettings: Object = {
palette: [
{ color: '#C06C84', label: 'Low', value: 50 },
{ color: '#6C5B7B', label: 'Moderate', value: 80 },
{ color: '#355C7D', label: 'High', value: 100 }
],
type: 'Gradient'
};
public legendSettings: Object = {
visible: true,
position: 'Bottom'
};
}Legend Events
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { HeatMapModule} from '@syncfusion/ej2-angular-heatmap'
import { TooltipService, LegendService} from '@syncfusion/ej2-angular-heatmap'
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMap, Tooltip, Legend, ILegendRenderEventArgs } from '@syncfusion/ej2-angular-heatmap';
HeatMap.Inject(Tooltip, Legend);
@Component({
imports: [ HeatMapModule ],
providers: [TooltipService, LegendService],
standalone: true,
selector: 'my-app',
template:
`<ejs-heatmap id='container' (legendRender)=(legendRender($event)) style="display:block;" [dataSource]='dataSource' [xAxis]='xAxis' [yAxis]='yAxis'
[titleSettings]='titleSettings'>
</ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
public legendRender(args: ILegendRenderEventArgs): void {
console.log("The legend render event has been triggered!!!");
}
public dataSource: Object[] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68],
[99, 28, 22, 4, 66, 90],
[14, 26, 97, 69, 69, 3],
[7, 46, 47, 47, 88, 6],
[41, 55, 73, 23, 3, 79],
[56, 69, 21, 86, 3, 33],
[45, 7, 53, 81, 95, 79],
[60, 77, 74, 68, 88, 51],
[25, 25, 10, 12, 78, 14],
[25, 56, 55, 58, 12, 82],
[74, 33, 88, 23, 86, 59]];
public titleSettings: Object = {
text: 'Sales Revenue per Employee (in 1000 US$)',
textStyle: {
size: '15px',
fontWeight: '500',
fontStyle: 'Normal',
fontFamily: 'Segoe UI'
}
};
public xAxis: Object = {
labels: ['Nancy', 'Andrew', 'Janet', 'Margaret', 'Steven',
'Michael', 'Robert', 'Laura', 'Anne', 'Paul', 'Karin', 'Mario'],
};
public yAxis: Object = {
labels: ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'],
};
}Best Practices
Do
- Use legend for value interpretation: Users should understand color meaning
- Position legend strategically: Bottom/Right for common left-to-right reading
- Format labels clearly: Include units (%, $, etc.)
- Use gradient legend for continuous data: More intuitive than fixed
- Test legend visibility: Especially important for color-blind users
Don't
- Don't hide legend entirely: Users need value context
- Don't use poor color contrast: Ensure readability
- Don't overlap legend with data: Give it dedicated space
- Don't use obscure label formats: Keep it simple and clear
- Don't ignore accessibility: Provide alternative representations
Visual Customization & Rendering
API Reference: references/api-reference.md
Table of Contents
- Color Palettes
- Custom Color Array
- Value-Based Color Mapping
- Gradient Palette (Continuous)
- Fixed Palette (Discrete)
- Example: Performance Heatmap
- Rendering Modes
- Auto Mode (Default)
- SVG Rendering
- Canvas Rendering
- Complete Rendering Example
- Cell Styling
- Cell Border and Background
- Bubble Heatmap Variation
- Bubble Heatmap Setup
- Bubble Type Options
- Responsive Design
- Responsive Container
- Adaptive Font Sizing
- Best Practices
- Do
- Don't
Color Palettes
HeatMap provides predefined palettes and custom color mapping options.
Custom Color Array
paletteSettings: any = {
type: 'Gradient',
palette: ['#FFFFFF', '#E3165B'] // White to deep pink
};
// Multi-color gradient
paletteSettings: any = {
type: 'Gradient',
palette: [
'#00008B', // Dark blue (low values)
'#0000CD', // Medium blue
'#1E90FF', // Dodger blue
'#87CEEB', // Sky blue
'#FFFFFF', // White (middle)
'#FFD700', // Gold
'#FFA500', // Orange
'#FF4500', // Orange-red
'#FF0000' // Red (high values)
]
};Value-Based Color Mapping
Map specific value ranges to specific colors.
Gradient Palette (Continuous)
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { HeatMapModule} from '@syncfusion/ej2-angular-heatmap'
import { LegendService} from '@syncfusion/ej2-angular-heatmap'
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
imports: [ HeatMapModule ],
providers: [ LegendService],
standalone: true,
selector: 'my-app',
template:
`<ejs-heatmap id='container' style="display:block;" [dataSource]='dataSource' [xAxis]='xAxis' [yAxis]='yAxis'
[titleSettings]='titleSettings' [paletteSettings]='paletteSettings' [legendSettings]='legendSettings'>
</ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent{
dataSource: Object[] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68],
[99, 28, 22, 4, 66, 90],
[14, 26, 97, 69, 69, 3],
[7, 46, 47, 47, 88, 6],
[41, 55, 73, 23, 3, 79],
[56, 69, 21, 86, 3, 33],
[45, 7, 53, 81, 95, 79],
[60, 77, 74, 68, 88, 51],
[25, 25, 10, 12, 78, 14],
[25, 56, 55, 58, 12, 82],
[74, 33, 88, 23, 86, 59]];
titleSettings: Object = {
text: 'Sales Revenue per Employee (in 1000 US$)',
textStyle: {
size: '15px',
fontWeight: '500',
fontStyle: 'Normal',
fontFamily: 'Segoe UI'
}
};
xAxis: Object = {
labels: ['Nancy', 'Andrew', 'Janet', 'Margaret', 'Steven',
'Michael', 'Robert', 'Laura', 'Anne', 'Paul', 'Karin', 'Mario'],
};
yAxis: Object = {
labels: ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'],
};
public paletteSettings: Object = {
palette: [
{ color: '#C06C84', label:'Low', value:50 },
{ color: '#6C5B7B', label:'Moderate', value:80 },
{ color: '#355C7D', label:'High', value: 100 }
],
type: "Gradient"
};
public legendSettings: Object = {
visible: true,
};
}Fixed Palette (Discrete)
paletteSettings: any = {
type: 'Fixed',
palette: [
{ value: 10, color: '#FF0000' }, // 0-10: Red (low)
{ value: 20, color: '#FFA500' }, // 10-20: Orange
{ value: 30, color: '#FFFF00' }, // 20-30: Yellow
{ value: 40, color: '#00FF00' }, // 30-40: Green
{ value: 50, color: '#00FF00' } // 40+: Dark Green (high)
]
};Example: Performance Heatmap
// Excellent: Green, Good: Light Green, Average: Yellow, Poor: Orange, Bad: Red
paletteSettings: any = {
type: 'Fixed',
palette: [
{ value: 60, color: '#FF0000' }, // <60: Red (Bad)
{ value: 70, color: '#FFA500' }, // 60-70: Orange (Poor)
{ value: 80, color: '#FFFF00' }, // 70-80: Yellow (Average)
{ value: 90, color: '#90EE90' }, // 80-90: Light Green (Good)
{ value: 100, color: '#00AA00' } // 90-100: Green (Excellent)
]
};Rendering Modes
Choose between SVG (scalable) and Canvas (performance) rendering.
Auto Mode (Default)
// Automatically switches based on data size
renderingMode: 'Auto' // SVG for small, Canvas for largeSVG Rendering
renderingMode: 'SVG' // Vector rendering, better for small datasetsAdvantages:
- Crisp, scalable output
- Better for printing
- Interactive features fully supported
- Smaller datasets (< 10k cells)
Disadvantages:
- Slower with large datasets
- DOM overhead
Canvas Rendering
renderingMode: 'Canvas' // Raster rendering, better for large datasetsAdvantages:
- High performance with large datasets
- Handles 100k+ cells efficiently
- Lower memory usage
- Faster rendering
Disadvantages:
- No built-in interactivity
- Lower visual quality when zoomed
Complete Rendering Example
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, TooltipService, LegendService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [TooltipService, LegendService],
template: `
<div class="control-section">
<div style="margin-bottom: 20px;">
<label style="font-weight: 600; margin-right: 10px;">Rendering Mode:</label>
<select (change)='changeRenderingMode($event)' style="padding: 5px; border-radius: 4px;">
<option value="Auto">Auto</option>
<option value="SVG">SVG</option>
<option value="Canvas">Canvas</option>
</select>
</div>
<ejs-heatmap id='heatmap'
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[renderingMode]='renderingMode'
[titleSettings]='titleSettings'>
</ejs-heatmap>
</div>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent implements OnInit {
// 100x100 2D Array (10,000 cells)
public dataSource: number[][] = [];
public renderingMode: string = 'Auto';
public xAxis: Object = {
title: { text: 'X-Axis Range' },
minimum: 0,
maximum: 99,
valueType: 'Numeric'
};
public yAxis: Object = {
title: { text: 'Y-Axis Range' },
minimum: 0,
maximum: 99,
valueType: 'Numeric'
};
public titleSettings: Object = {
text: 'Performance Test: 10,000 Cells',
textStyle: { size: '15px', fontWeight: '500' }
};
ngOnInit(): void {
// Initialize 100x100 2D array
const data: number[][] = [];
for (let i = 0; i < 100; i++) {
data[i] = [];
for (let j = 0; j < 100; j++) {
data[i][j] = Math.floor(Math.random() * 100);
}
}
this.dataSource = data;
}
// Updates the rendering engine dynamically
public changeRenderingMode(event: any): void {
this.renderingMode = event.target.value;
}
}Cell Styling
Customize individual cell appearance.
Cell Border and Background
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, TooltipService, LegendService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [TooltipService, LegendService],
template: `
<ejs-heatmap id='heatmap'
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[cellSettings]='cellSettings'
[titleSettings]='titleSettings'>
</ejs-heatmap>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
// 2D Datasource: Rows are Products, Columns are Quarters
public dataSource: number[][] = [
[10, 15], // Product A: Q1, Q2
[20, 25] // Product B: Q1, Q2
];
public xAxis: Object = {
valueType: 'Category',
labels: ['Q1', 'Q2']
};
public yAxis: Object = {
valueType: 'Category',
labels: ['Product A', 'Product B']
};
public titleSettings: Object = {
text: 'Styled Revenue HeatMap',
textStyle: { size: '15px', fontWeight: '500', fontFamily: 'Segoe UI' }
};
public cellSettings: Object = {
showLabel: true,
// Correction: property is 'format', not 'labelFormat'
format: '${value}K',
border: {
color: '#333333',
width: 2
},
textStyle: {
color: '#000000',
size: '14px',
fontFamily: 'Segoe UI'
}
};
}Bubble Heatmap Variation
Use bubbles instead of rectangular cells for alternative visualization.
Bubble Heatmap Setup
import { Component, ViewEncapsulation } from '@angular/core';
import {
HeatMapModule,
LegendService,
TooltipService
} from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [LegendService, TooltipService],
template: `
<ejs-heatmap id='container' style="display:block;"
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[titleSettings]='titleSettings'
[paletteSettings]='paletteSettings'
[cellSettings]='cellSettings'
[legendSettings]='legendSettings'>
</ejs-heatmap>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
// 2D Array Datasource (12 Rows x 6 Columns)
public dataSource: number[][] = [
[73, 39, 26, 39, 94, 0],
[93, 58, 53, 38, 26, 68],
[99, 28, 22, 4, 66, 90],
[14, 26, 97, 69, 69, 3],
[7, 46, 47, 47, 88, 6],
[41, 55, 73, 23, 3, 79],
[56, 69, 21, 86, 3, 33],
[45, 7, 53, 81, 95, 79],
[60, 77, 74, 68, 88, 51],
[25, 25, 10, 12, 78, 14],
[25, 56, 55, 58, 12, 82],
[74, 33, 88, 23, 86, 59]
];
public titleSettings: Object = {
text: 'Sales Revenue per Employee (in 1000 US$)',
textStyle: {
size: '15px',
fontWeight: '500',
fontFamily: 'Segoe UI'
}
};
public xAxis: Object = {
labels: ['Nancy', 'Andrew', 'Janet', 'Margaret', 'Steven', 'Michael', 'Robert', 'Laura', 'Anne', 'Paul', 'Karin', 'Mario'],
valueType: 'Category'
};
public yAxis: Object = {
labels: ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'],
valueType: 'Category'
};
public paletteSettings: Object = {
palette: [
{ color: '#C06C84' },
{ color: '#6C5B7B' },
{ color: '#355C7D' }
],
type: 'Gradient'
};
public cellSettings: Object = {
border: { width: 1 },
showLabel: false,
// Configures the heatmap to render bubbles instead of rectangles
tileType: 'Bubble',
bubbleType: 'Size'
};
public legendSettings: Object = {
visible: true,
position: 'Bottom'
};
}Bubble Type Options
// Size-based bubbles
cellSettings: any = {
bubbleType: 'Size' // Larger bubbles = higher values
};
// Color and size both encode values
cellSettings: any = {
bubbleType: 'SizeAndColor' // Use both dimensions
};
// Multiple bubble representations
cellSettings: any = {
bubbleType: 'Sector' // Pie slice representation
};Responsive Design
Make heatmaps responsive to different screen sizes.
Responsive Container
import { Component, ViewEncapsulation } from '@angular/core';
import { HeatMapModule, TooltipService, LegendService } from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [TooltipService, LegendService],
template: `
<div class='heatmap-container'>
<ejs-heatmap id='heatmap'
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[titleSettings]='titleSettings'
width='100%'
height='100%'>
</ejs-heatmap>
</div>
`,
styles: [`
/* Container defines the responsive boundaries */
.heatmap-container {
width: 100%;
height: 500px;
margin: 20px 0;
border: 1px solid #eee;
}
/* Tablets */
@media (max-width: 768px) {
.heatmap-container {
height: 350px;
}
}
/* Mobile Devices */
@media (max-width: 480px) {
.heatmap-container {
height: 250px;
}
}
`],
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
// 2D Datasource for reliable mapping
public dataSource: number[][] = [
[10, 15], // Product A: Q1, Q2
[20, 25] // Product B: Q1, Q2
];
public xAxis: Object = {
valueType: 'Category',
labels: ['Q1', 'Q2']
};
public yAxis: Object = {
valueType: 'Category',
labels: ['Product A', 'Product B']
};
public titleSettings: Object = {
text: 'Responsive Sales Performance',
textStyle: { size: '15px', fontWeight: '500' }
};
}Adaptive Font Sizing
import { Component, ViewEncapsulation } from '@angular/core';
import {
HeatMapModule,
TooltipService,
LegendService,
ILoadedEventArgs
} from '@syncfusion/ej2-angular-heatmap';
@Component({
selector: 'my-app',
standalone: true,
imports: [HeatMapModule],
providers: [TooltipService, LegendService],
template: `
<div id='heatmap-container' style="width: 100%; height: 400px;">
<ejs-heatmap id='heatmap'
[dataSource]='dataSource'
[xAxis]='xAxis'
[yAxis]='yAxis'
[cellSettings]='cellSettings'
(load)='onHeatMapLoad($event)'>
</ejs-heatmap>
</div>
`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
private heatmapInstance: any;
// 2D Datasource: [Product A: Q1, Q2], [Product B: Q1, Q2]
public dataSource: number[][] = [
[45, 52],
[38, 41]
];
public xAxis: Object = { valueType: 'Category', labels: ['Q1', 'Q2'] };
public yAxis: Object = { valueType: 'Category', labels: ['Product A', 'Product B'] };
public cellSettings: any = {
showLabel: true,
textStyle: {
size: '14px',
fontFamily: 'Segoe UI'
}
};
/**
* Triggered before the heatmap is rendered.
* We capture the instance and adjust settings based on the container width.
*/
public onHeatMapLoad(args: ILoadedEventArgs): void {
this.heatmapInstance = args.heatmap;
const container = document.getElementById('heatmap-container');
if (container && this.heatmapInstance) {
const width = container.clientWidth;
// Logic to adjust font size dynamically based on pixel width
if (width < 500) {
this.cellSettings.textStyle.size = '10px';
} else if (width < 800) {
this.cellSettings.textStyle.size = '12px';
} else {
this.cellSettings.textStyle.size = '14px';
}
}
}
}Best Practices
Do
- Use appropriate color palettes: Red-yellow-green for performance, viridis for general data
- Test rendering mode: Use Auto or Canvas for large datasets
- Ensure color contrast: Especially for accessibility
- Label cells clearly: Show values inside or via tooltips
- Make responsive: Works on mobile and desktop
Don't
- Don't use rainbow palette indiscriminately: Can be hard to interpret
- Don't force SVG mode on large datasets: Causes performance issues
- Don't use low contrast colors: Accessibility issues
- Don't add too many visual effects: Can distract from data
- Don't ignore color blindness: Test with accessibility tools