JavaScript Responsive HTML Annotations Example

Demonstrates how to use the HtmlCustomAnnotation to create responsive text content using SciChart.js, High Performance JavaScript Charts

Fullscreen

Edit

 Edit

Docs

drawExample.ts

index.html

vanilla.ts

theme.ts

Copy to clipboard
Minimise
Fullscreen
1import {
2    HtmlCustomAnnotation,
3    CategoryAxis,
4    EAnnotationLayer,
5    ECoordinateMode,
6    EHorizontalAnchorPoint,
7    EVerticalAnchorPoint,
8    EXyDirection,
9    MouseWheelZoomModifier,
10    NumberRange,
11    NumericAxis,
12    SciChartSurface,
13    ZoomPanModifier,
14    SmartDateLabelProvider,
15    AnnotationHoverModifier,
16    HtmlTextAnnotation,
17    AnnotationBase,
18    easing,
19    EHoverMode,
20    GenericAnimation,
21    translateFromCanvasToSeriesViewRect,
22    translateToNotScaled,
23    IAnnotation,
24} from "scichart";
25
26import "./styles.css";
27import { appTheme } from "../../../theme";
28
29const data1 = [
30    {
31        start: 1745830800,
32        end: 1745834400,
33        title: "Standup Meeting",
34        color: "#FF6B6B",
35    },
36    {
37        start: 1745834400,
38        end: 1745838900,
39        title: "Planning Session",
40        color: "#4ECDC4",
41    },
42    {
43        start: 1745838900,
44        end: 1745842500,
45        title: "Lunch Break",
46        color: "#FFD93D",
47    },
48    {
49        start: 1745842500,
50        end: 1745847900,
51        title: "Presentation Prep",
52        color: "#1A535C",
53    },
54    {
55        start: 1745847900,
56        end: 1745851500,
57        title: "One-on-One Meeting",
58        color: "#FF9F1C",
59    },
60    {
61        start: 1745851500,
62        end: 1745855100,
63        title: "Email Responses",
64        color: "#6A4C93",
65    },
66];
67
68const data2 = [
69    {
70        start: 1745830800,
71        end: 1745832600,
72        title: "Morning Sync",
73        color: "#FFB5E8",
74    },
75    {
76        start: 1745832600,
77        end: 1745836200,
78        title: "Design Review",
79        color: "#B5EAD7",
80    },
81    {
82        start: 1745836200,
83        end: 1745839800,
84        title: "Code Implementation",
85        color: "#C7CEEA",
86    },
87    {
88        start: 1745839800,
89        end: 1745843400,
90        title: "Lunch + Walk",
91        color: "#FFDAC1",
92    },
93    {
94        start: 1745843400,
95        end: 1745848800,
96        title: "Dev Handoff",
97        color: "#E2F0CB",
98    },
99    {
100        start: 1745848800,
101        end: 1745855100,
102        title: "Documentation",
103        color: "#FFABAB",
104    },
105];
106
107const data3 = [
108    {
109        start: 1745830800,
110        end: 1745833500,
111        title: "Daily Briefing",
112        color: "#FFD6A5",
113    },
114    {
115        start: 1745833500,
116        end: 1745838000,
117        title: "UX Interviews",
118        color: "#9BF6FF",
119    },
120    {
121        start: 1745838000,
122        end: 1745842500,
123        title: "Lunch & Networking",
124        color: "#A0C4FF",
125    },
126    {
127        start: 1745842500,
128        end: 1745846100,
129        title: "Sprint Planning",
130        color: "#BDB2FF",
131    },
132    {
133        start: 1745846100,
134        end: 1745849700,
135        title: "Code Review",
136        color: "#FFC6FF",
137    },
138    {
139        start: 1745849700,
140        end: 1745855100,
141        title: "Backlog Grooming",
142        color: "#FFFFD1",
143    },
144];
145
146const data4 = [
147    {
148        start: 1745830800,
149        end: 1745834100,
150        title: "System Check-In",
151        color: "#FFADAD",
152    },
153    {
154        start: 1745834100,
155        end: 1745837700,
156        title: "Architecture Planning",
157        color: "#FFD6A5",
158    },
159    {
160        start: 1745837700,
161        end: 1745842200,
162        title: "Lunch Break",
163        color: "#FDFFB6",
164    },
165    {
166        start: 1745842200,
167        end: 1745846700,
168        title: "Testing Session",
169        color: "#CAFFBF",
170    },
171    {
172        start: 1745846700,
173        end: 1745851200,
174        title: "QA Sync",
175        color: "#9BF6FF",
176    },
177    {
178        start: 1745851200,
179        end: 1745855100,
180        title: "End-of-Day Recap",
181        color: "#A0C4FF",
182    },
183];
184
185export const drawExample = async (rootElement: string | HTMLDivElement) => {
186    const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement);
187    const xAxis = new CategoryAxis(wasmContext, {
188        isInnerAxis: true,
189        labelStyle: {
190            color: "black",
191            fontSize: 12,
192        },
193        majorGridLineStyle: {
194            color: "gray",
195            strokeDashArray: [2, 2],
196        },
197        drawMinorGridLines: false,
198        drawMajorBands: false,
199        labelProvider: new SmartDateLabelProvider({ rotation: -90 }),
200        visibleRangeLimit: new NumberRange(data1[0].start - 4 * 24 * 60, data1[data1.length - 1].end + 4 * 24 * 60),
201        visibleRange: new NumberRange(data1[0].start, data1[data1.length - 1].end),
202    });
203    const yAxis = new NumericAxis(wasmContext, { isVisible: false });
204
205    sciChartSurface.xAxes.add(xAxis);
206    sciChartSurface.yAxes.add(yAxis);
207
208    sciChartSurface.chartModifiers.add(
209        new ZoomPanModifier({ xyDirection: EXyDirection.XDirection }),
210        new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection })
211    );
212
213    const crateTimeSlotAnnotation =
214        (offset: number) =>
215        ({ start, end, title, color }: any) => {
216            const textAnnotation = new HtmlCustomAnnotation({
217                // move to the background to allow drawing grid lines and labels above the annotations
218                annotationLayer: EAnnotationLayer.Background,
219                yCoordinateMode: ECoordinateMode.Relative,
220                x1: start,
221                y1: offset * 0.25,
222                x2: end,
223                y2: (offset + 1) * 0.25,
224                horizontalAnchorPoint: EHorizontalAnchorPoint.Center,
225                verticalAnchorPoint: EVerticalAnchorPoint.Center,
226            });
227
228            textAnnotation.htmlElement.innerHTML = `<div class="responsiveTextAnnotation">${title}</div>`;
229            textAnnotation.htmlElement.classList.add("responsiveTextAnnotationContainer");
230            textAnnotation.htmlElement.style.background = color;
231            return textAnnotation;
232        };
233
234    const annotations1 = data1.map(crateTimeSlotAnnotation(0));
235    const annotations2 = data2.map(crateTimeSlotAnnotation(1));
236    const annotations3 = data3.map(crateTimeSlotAnnotation(2));
237    const annotations4 = data4.map(crateTimeSlotAnnotation(3));
238
239    const titleAnnotation1 = addLaneTitleAnnotation("Employee1", "#FFB6C1", 0);
240    const titleAnnotation2 = addLaneTitleAnnotation("Employee2", "#40E0D0", 0.25);
241    const titleAnnotation3 = addLaneTitleAnnotation("Employee3", "#6A5ACD", 0.5);
242    const titleAnnotation4 = addLaneTitleAnnotation("Employee4", "#ADFF2F", 0.75);
243
244    sciChartSurface.annotations.add(
245        ...annotations1,
246        ...annotations2,
247        ...annotations3,
248        ...annotations4,
249        titleAnnotation1,
250        titleAnnotation2,
251        titleAnnotation3,
252        titleAnnotation4
253    );
254
255    addTooltipForAnnotations(sciChartSurface, [...annotations1, ...annotations2, ...annotations3, ...annotations4]);
256
257    return { sciChartSurface };
258};
259
260function addLaneTitleAnnotation(text: string, background: string, yOffset: number) {
261    return new HtmlTextAnnotation({
262        x1: 0,
263        y1: yOffset,
264        xCoordinateMode: ECoordinateMode.Relative,
265        yCoordinateMode: ECoordinateMode.Relative,
266        horizontalAnchorPoint: EHorizontalAnchorPoint.Left,
267        verticalAnchorPoint: EVerticalAnchorPoint.Top,
268        textContainerStyle: {
269            fontSize: "10px",
270            color: "black",
271            opacity: "0.7",
272            background,
273        },
274        text,
275    });
276}
277
278function addTooltipForAnnotations(sciChartSurface: SciChartSurface, targets: IAnnotation[]) {
279    const tooltipAnnotation = new HtmlTextAnnotation({
280        x1: 0,
281        y1: 0,
282        xCoordShift: 20,
283        yCoordShift: 20,
284        xCoordinateMode: ECoordinateMode.Pixel,
285        yCoordinateMode: ECoordinateMode.Pixel,
286        horizontalAnchorPoint: EHorizontalAnchorPoint.Left,
287        verticalAnchorPoint: EVerticalAnchorPoint.Top,
288        textContainerStyle: {
289            fontSize: "12px",
290            color: appTheme.ForegroundColor,
291            padding: "4px",
292            background: "rgba(0, 0, 139, 0.4)",
293            backdropFilter: "blur(10px)",
294            borderRadius: "0px 15px 15px 15px",
295        },
296        text: "",
297        isHidden: true,
298    });
299
300    sciChartSurface.modifierAnnotations.add(tooltipAnnotation);
301
302    let currentTooltipAnimation: GenericAnimation<number>;
303    const animateTooltip = () => {
304        currentTooltipAnimation?.cancel();
305        tooltipAnnotation.isHidden = true;
306        currentTooltipAnimation = new GenericAnimation<number>({
307            from: 0,
308            to: 1,
309            duration: 0,
310            delay: 500,
311            ease: easing.linear,
312            onAnimate: (from: number, to: number, progress) => {},
313            onCompleted: () => {
314                tooltipAnnotation.isHidden = false;
315            },
316        });
317        sciChartSurface.addAnimation(currentTooltipAnimation);
318    };
319
320    const annotationHoverModifier = new AnnotationHoverModifier({
321        // check hover on provided annotations
322        targets,
323        // ignore tooltip annotation if it is overlapping with other
324        hoverMode: EHoverMode.TopmostIncluded,
325        // needed to update tooltip position when moving the cursor within an annotation
326        notifyPositionUpdate: true,
327        // manage tooltip visibility and position
328        onHover: (args) => {
329            const [hoveredAnnotation] = args.hoveredEntities as AnnotationBase[];
330            if (hoveredAnnotation) {
331                if (hoveredAnnotation.isEditable) {
332                    sciChartSurface.domChartRoot.style.cursor = "grab";
333                }
334                if (hoveredAnnotation.isDraggingStarted) {
335                    tooltipAnnotation.isHidden = true;
336                    return;
337                }
338
339                const borders = tooltipAnnotation.getAnnotationBorders(true);
340                tooltipAnnotation.text = `${formatTime(hoveredAnnotation.x1)} - ${formatTime(hoveredAnnotation.x2)}`;
341
342                const handleAnnotationsOutsideSeriesViewRect = true;
343                const translatedMousePoint = translateFromCanvasToSeriesViewRect(
344                    args.mouseArgs.mousePoint,
345                    sciChartSurface.seriesViewRect,
346                    handleAnnotationsOutsideSeriesViewRect
347                );
348                tooltipAnnotation.x1 = translateToNotScaled(translatedMousePoint.x);
349                tooltipAnnotation.y1 = translateToNotScaled(translatedMousePoint.y);
350
351                // initial default offset from pointer
352                tooltipAnnotation.xCoordShift = 20;
353                const width = Math.abs(borders.x2 - borders.x1);
354                const expectedX2Coordinate = tooltipAnnotation.x1 + tooltipAnnotation.xCoordShift + width;
355                const unscaledViewWidth = translateToNotScaled(sciChartSurface.seriesViewRect.width);
356                if (expectedX2Coordinate > unscaledViewWidth) {
357                    tooltipAnnotation.xCoordShift = unscaledViewWidth - width - tooltipAnnotation.x1;
358                }
359
360                animateTooltip();
361            } else {
362                sciChartSurface.domChartRoot.style.cursor = "auto";
363                tooltipAnnotation.isHidden = true;
364                currentTooltipAnimation?.cancel();
365            }
366        },
367    });
368
369    sciChartSurface.chartModifiers.add(annotationHoverModifier);
370}
371
372function formatTime(timestamp: number) {
373    const date = new Date(timestamp * 1000);
374    const hours = date.getHours().toString().padStart(2, "0");
375    const minutes = date.getMinutes().toString().padStart(2, "0");
376    return `${hours}:${minutes}`;
377}
378

Responsive HTML Annotations Example - JavaScript

Overview

This example demonstrates responsive HTML annotations in SciChart.js, creating an interactive schedule visualization with time-bound annotations. It showcases HtmlCustomAnnotation and HtmlTextAnnotation to display employee schedules with CSS container queries for responsive text layout.

Technical Implementation

The implementation uses CategoryAxis with SmartDateLabelProvider for time-based data. Annotations are positioned using ECoordinateMode with responsive CSS that adapts text orientation based on container size. An AnnotationHoverModifier provides interactive tooltips with time formatting.

Features and Capabilities

Key features include: dynamic annotation sizing, CSS-based responsive text layout, interactive hover tooltips, and multi-lane schedule visualization. The example leverages modern CSS features like container queries and viewport units for responsive behavior.

Integration and Best Practices

The implementation shows best practices for time-based data visualization, including proper axis configuration and annotation layering using EAnnotationLayer. Performance is maintained by limiting DOM updates during interactions.

javascript Chart Examples & Demos

See Also: Charts added in v4 (16 Demos)

JavaScript Histogram Chart | Javascript Charts | SciChart.js

JavaScript Histogram Chart

Create a JavaScript Histogram Chart with custom texture fills and patterns. Try the SciChart.js library for seamless integration today.

JavaScript Gantt Chart | Javascript Charts | SciChart.js Demo

JavaScript Gantt Chart Example

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

JavaScript Choropleth Map | Javascript Charts | SciChart.js Demo

JavaScript Choropleth Map Example

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

JavaScript Multi-Layer Map | Javascript Charts | SciChart.js

JavaScript Multi-Layer Map Example

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

JavaScript Animated Bar Chart | Javascript Charts | SciChart.js

JavaScript Animated Bar Chart Example

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

JavaScript Vector Field Plot | Javascript Charts | SciChart.js

JavaScript Vector Field Plot

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

JavaScript Waterfall Chart | Bridge Chart | SciChart.js

JavaScript Waterfall Chart | Bridge Chart

Build a JavaScript Waterfall Chart with dynamic coloring, multi-line data labels and responsive design. Try SciChart.js for seamless integration today.

JavaScript Box Plot Chart | Javascript Charts | SciChart.js Demo

JavaScript Box Plot Chart

Try the JavaScript Box-Plot Chart examples with developer-friendly chart lifecycle management, dynamic sub-surface positioning, and custom styling.

JavaScript Triangle Series | Triangle Mesh Chart | SciChart

JavaScript Triangle Series | Triangle Mesh Chart

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

JavaScript Treemap Chart | Javascript Charts | SciChart.js Demo

JavaScript Treemap Chart

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

NEW!
JavaScript Map Chart with Heatmap overlay | SciChart.js

JavaScript Map Chart with Heatmap overlay

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

Realtime Audio Analyzer Bars Demo | SciChart.js Demo

Realtime Audio Analyzer Bars Demo

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

JavaScript Linear Gauges | Javascript Charts | SciChart.js Demo

JavaScript Linear Gauges Example

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

NEW!
JavaScript Order of Rendering | Javascript Charts | SciChart.js

JavaScript Order of Rendering Example

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

HTML Annotations and Custom in-chart Controls | SciChart

HTML Annotations and Custom in-chart Controls Example

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

JavaScript Polar Modifiers | Polar Interactivity Modifiers

JavaScript Polar Modifiers | Polar Interactivity Modifiers Demo

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

SciChart Ltd, 16 Beaufort Court, Admirals Way, Docklands, London, E14 9XL.