Creates an Angular Histogram Chart using SciChart.js, by leveraging the FastRectangleRenderableSeries, and its customTextureOptions property to have a custom tiling texture fill.
drawExample.ts
angular.ts
theme.ts
1import {
2 NumericAxis,
3 ZoomPanModifier,
4 ZoomExtentsModifier,
5 MouseWheelZoomModifier,
6 SciChartSurface,
7 ENumericFormat,
8 EAxisAlignment,
9 FastRectangleRenderableSeries,
10 XyxyDataSeries,
11 EColumnYMode,
12 EColumnMode,
13 EDataPointWidthMode,
14 NumberRange,
15 EHorizontalTextPosition,
16 EVerticalTextPosition,
17 ICustomTextureOptions,
18} from "scichart";
19import { appTheme } from "../../../theme";
20
21// Population data by age range
22const populationData = {
23 xValues: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100],
24 yValues: {
25 male: [
26 4869936, 5186991, 5175063, 5286053, 5449038, 5752398, 6168124, 6375035, 6265554, 5900833, 6465830, 7108184,
27 6769524, 5676968, 4828153, 3734266, 2732054, 1633630, 587324, 128003, 12023,
28 ],
29 female: [
30 4641147, 4940521, 5010242, 5010526, 5160160, 5501673, 6022599, 6329356, 6299693, 5930345, 6509757, 7178487,
31 7011569, 6157651, 5547296, 4519433, 3704145, 2671974, 1276597, 399148, 60035,
32 ],
33 },
34};
35
36const BREAK_POINTS = [0, 20, 30, 45, 65, 70, 80];
37
38function prepareRectangleData() {
39 const totalData = populationData.xValues.map((xValue, index) => {
40 const total = populationData.yValues.male[index] + populationData.yValues.female[index];
41 return { xValue, yValue: total };
42 });
43
44 // Prepare data for each range
45 const xValues: number[] = [];
46 const yValues: number[] = [];
47 const x1Values: number[] = [];
48 const y1Values: number[] = [];
49
50 BREAK_POINTS.forEach((breakPoint, index) => {
51 let nextBreakPoint = BREAK_POINTS[index + 1];
52
53 if (nextBreakPoint === undefined) {
54 nextBreakPoint = 100; // Set the last range
55 }
56
57 const rangePopulation = totalData
58 .filter((data) => {
59 return data.xValue >= breakPoint && data.xValue < nextBreakPoint;
60 })
61 .reduce((sum, data) => sum + data.yValue, 0);
62
63 xValues.push(breakPoint);
64 yValues.push(rangePopulation);
65 x1Values.push(nextBreakPoint);
66 y1Values.push(0); // Set y1 to 0 for the bottom of the rectangle
67 });
68
69 return { xValues, yValues, x1Values, y1Values };
70}
71
72class StickFigureTextureOptions implements ICustomTextureOptions {
73 options: { stroke: string };
74 textureHeight: number = 48;
75 textureWidth: number = 48;
76 repeat?: boolean = true;
77
78 public constructor(options: { stroke: string; repeat: boolean; textureHeight: number; textureWidth: number }) {
79 this.options = options;
80 this.textureHeight = options.textureHeight;
81 this.textureWidth = options.textureWidth;
82 }
83
84 public createTexture(
85 context: CanvasRenderingContext2D,
86 options: { fill: string; opacity: number; stroke: string }
87 ) {
88 context.fillStyle = options.fill;
89 context.fillRect(0, 0, this.textureWidth, this.textureHeight);
90 context.strokeStyle = options.stroke;
91
92 // Set up transformation: move to center, rotate, move back for
93 context.translate(this.textureWidth / 2, this.textureHeight / 2);
94 context.translate(-this.textureWidth / 2, -this.textureHeight / 2);
95
96 // Proportional values
97 const centerX = this.textureWidth / 2;
98 const headRadius = Math.min(this.textureWidth, this.textureHeight) * 0.16; // 16% of smaller dimension
99 const headY = this.textureHeight * 0.25;
100 const bodyTopY = headY + headRadius;
101 const bodyBottomY = this.textureHeight * 0.63;
102 const armY = bodyTopY + this.textureHeight * 0.06;
103 const armSpan = this.textureWidth * 0.38; // arms reach out 19% each side
104 const legY = bodyBottomY;
105 const legSpan = this.textureWidth * 0.25; // legs out 12.5% each side
106 const legBottomY = this.textureHeight * 0.97;
107
108 // Head
109 context.beginPath();
110 context.arc(centerX, headY, headRadius, 0, Math.PI * 2);
111 context.stroke();
112
113 // Body
114 context.beginPath();
115 context.moveTo(centerX, bodyTopY);
116 context.lineTo(centerX, bodyBottomY);
117 context.stroke();
118
119 // Left Arm
120 context.beginPath();
121 context.moveTo(centerX, armY);
122 context.lineTo(centerX - armSpan, armY + this.textureHeight * 0.09);
123 context.stroke();
124
125 // Right Arm
126 context.beginPath();
127 context.moveTo(centerX, armY);
128 context.lineTo(centerX + armSpan, armY + this.textureHeight * 0.09);
129 context.stroke();
130
131 // Left Leg
132 context.beginPath();
133 context.moveTo(centerX, legY);
134 context.lineTo(centerX - legSpan, legBottomY);
135 context.stroke();
136
137 // Right Leg
138 context.beginPath();
139 context.moveTo(centerX, legY);
140 context.lineTo(centerX + legSpan, legBottomY);
141 context.stroke();
142 }
143}
144
145export const drawExample = async (rootElement: string | HTMLDivElement) => {
146 // Create a SciChartSurface
147 const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
148 theme: appTheme.SciChartJsTheme,
149 title: "Europe Population Distribution by Age Range",
150 titleStyle: {
151 fontSize: 24,
152 },
153 });
154
155 // Add X-axis
156 const xAxis = new NumericAxis(wasmContext, {
157 axisTitle: "Age Range (Years)",
158 autoTicks: false,
159 majorDelta: 5,
160 drawMajorBands: false,
161 drawMinorGridLines: false,
162 drawMajorTickLines: false,
163 drawMinorTickLines: false,
164 axisTitleStyle: {
165 fontSize: 13,
166 fontFamily: "Arial",
167 color: "#ffffff",
168 fontStyle: "italic",
169 },
170 growBy: new NumberRange(0.02, 0.02),
171 });
172 xAxis.labelProvider.formatLabel = (value: number) => {
173 // Custom label formatter to improve readability
174 if (BREAK_POINTS.includes(value)) {
175 return value.toString();
176 }
177 if (value === 100) {
178 return "100+";
179 }
180 return null;
181 };
182 sciChartSurface.xAxes.add(xAxis);
183
184 // Add Y-axis
185 const yAxis = new NumericAxis(wasmContext, {
186 axisTitle: "Population (Millions)",
187 labelFormat: ENumericFormat.Engineering,
188 axisAlignment: EAxisAlignment.Left,
189 drawMajorBands: false,
190 drawMinorGridLines: false,
191 drawMajorGridLines: true,
192 drawMajorTickLines: false,
193 drawMinorTickLines: false,
194 axisTitleStyle: {
195 fontSize: 14,
196 fontFamily: "Arial",
197 color: "#ffffff",
198 fontStyle: "italic",
199 },
200 growBy: new NumberRange(0.01, 0.1),
201 });
202 sciChartSurface.yAxes.add(yAxis);
203
204 // Prepare data and create rectangle series
205 const { xValues, yValues, x1Values, y1Values } = prepareRectangleData();
206
207 const rectangleSeries = new FastRectangleRenderableSeries(wasmContext, {
208 dataSeries: new XyxyDataSeries(wasmContext, {
209 xValues,
210 yValues,
211 x1Values,
212 y1Values,
213 }),
214 columnXMode: EColumnMode.StartEnd,
215 columnYMode: EColumnYMode.TopBottom,
216 dataPointWidthMode: EDataPointWidthMode.Range,
217 stroke: appTheme.DarkIndigo,
218 opacity: 0.8,
219 fill: appTheme.MutedSkyBlue,
220 topCornerRadius: 8,
221 bottomCornerRadius: 0,
222 customTextureOptions: new StickFigureTextureOptions({
223 stroke: appTheme.MutedBlue,
224 repeat: true,
225 textureWidth: 40,
226 textureHeight: 40,
227 }),
228 dataLabels: {
229 color: appTheme.DarkIndigo,
230 style: {
231 fontSize: 16,
232 },
233 precision: 0,
234 numericFormat: ENumericFormat.Engineering,
235 verticalTextPosition: EVerticalTextPosition.Above,
236 horizontalTextPosition: EHorizontalTextPosition.Right,
237 },
238 });
239 sciChartSurface.renderableSeries.add(rectangleSeries);
240
241 // Adjust the size of the custom texture so it scales as you zoom
242 sciChartSurface.layoutMeasured.subscribe((data) => {
243 const width = xAxis.getCurrentCoordinateCalculator().getCoordWidth(5);
244 const height = yAxis.getCurrentCoordinateCalculator().getCoordWidth(10000000);
245 if (
246 width !== rectangleSeries.customTextureOptions.textureWidth ||
247 height !== rectangleSeries.customTextureOptions.textureHeight
248 ) {
249 rectangleSeries.customTextureOptions = new StickFigureTextureOptions({
250 stroke: appTheme.MutedBlue,
251 repeat: true,
252 textureWidth: width,
253 textureHeight: height,
254 });
255 }
256 });
257
258 // Add interactivity modifiers
259 sciChartSurface.chartModifiers.add(new ZoomPanModifier(), new ZoomExtentsModifier(), new MouseWheelZoomModifier());
260
261 return { sciChartSurface, wasmContext };
262};
263This standalone Angular component showcases a Histogram Chart using SciChart.js to display population distribution data. The example uses the scichart-angular package for Angular integration.
The chart is implemented in drawExample.ts and integrated via Angular's template syntax: <scichart-angular [initChart]="drawExample"></scichart-angular>. The component uses FastRectangleRenderableSeries with custom textures and data labels.
The chart features age-range aggregation, custom stick-figure textures, and engineering-format labels. Interactive modifiers like ZoomExtentsModifier enhance user experience.
The example follows Angular standalone component patterns and demonstrates proper resource cleanup.

Build an Angular Gantt Chart with SciChart. View the demo for horizontal bars, rounded corners and data labels to show project timelines and task completion.

Create an Angular Choropleth map, a type of thematic map where areas are shaded or patterned in proportion to the value of a variable being represented.

Create a Angular Multi-Layer Map Example, using FastTriangleRenderableSeries with GeoJSON data-points using a constrained delaunay triangulation algorithm.

Bring annual comparison data to life with the Angular Animated Bar Chart example from SciChart. This demo showcases top 10 tennis players from 1990 to 2024.

View the Angular Vector Field Plot example from SciChart, including dynamic vector generation, gradient-colored segments, and interactive zoom/pan. Try demo.

Build an Angular Waterfall Chart with dynamic coloring, multi-line data labels & responsive design, using ScichartAngular component for seamless integration

Try the Angular Box Plot Chart example for Angular-friendly chart lifecycle management, dynamic sub-surface positioning, and custom styling. Try the demo now.

Create Angular Triangle Meshes with the Triangle Series from SciChart. This demo supports strip mode, list mode and the drawing of polygons. View the example.

Create an Angular Treemap Chart to define rectangle positions based on total value. Use SciChart FastRectangleRenderableSeries and d3-hierarchy.js layouts.

Design a highly dynamic Angular Map Chart with Heatmap overlay with SciChart's feature-rich JavaScript Chart Library. Get your free demo today.

Demonstrating the capability of SciChart.js to create a JavaScript Audio Analyzer Bars and visualize the Fourier-Transform of an audio waveform in realtime.

View the Angular Linear Gauge Chart example to combine rectangles & annotations. Create a linear gauge dashboard with animated indicators and custom scales.

The Angular Order of Rendering example gives you full control of the draw order of series and annotations for charts. Try SciChart's advanced customizations.

Build Responsive Angular HTML Annotations with SciChart. Use the advanced CSS container queries for responsive text layout and custom design. View demo now.

Angular HTML Chart Control example demonstrates advanced HTML annotation integration and how to render HTML components within charts. Try the SciChart demo.

Explore SciChart's Polar Interactivity Modifiers including zooming, panning, and cursor tracking. Try the demo to trial the Polar Chart Behavior Modifiers.