diff --git a/pages/03-core/heatmap.page.tsx b/pages/03-core/heatmap.page.tsx new file mode 100644 index 00000000..22af22f3 --- /dev/null +++ b/pages/03-core/heatmap.page.tsx @@ -0,0 +1,125 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import CoreChart from "../../lib/components/internal-do-not-use/core-chart"; +import { Page } from "../common/templates"; +import { useHighcharts } from "../common/use-highcharts"; +import pseudoRandom from "../utils/pseudo-random"; + +const INSTANCE_COUNT = 10; +const PERIOD = 60000; // 1 minute in ms +const POINTS_PER_INSTANCE = 100; +const START_TIME = Date.now() - POINTS_PER_INSTANCE * PERIOD; + +function generateHeatmapData() { + const instances = Array.from({ length: INSTANCE_COUNT }, (_, i) => `i-${String(i).padStart(16, "0")}`); + + const series = instances.map((name, yIndex) => { + const baseValue = 0.5 + pseudoRandom() * 2.5; + const data: [number, number, number][] = []; + for (let x = 0; x < POINTS_PER_INSTANCE; x++) { + const timestamp = START_TIME + x * PERIOD; + const value = baseValue + (pseudoRandom() - 0.5) * 0.5; + data.push([timestamp, yIndex, value]); + } + return { + name, + type: "heatmap" as const, + data, + borderWidth: 0, + borderRadius: 0, + pointPadding: 0, + showInLegend: false, + colsize: PERIOD, + }; + }); + + return { series, instances }; +} + +const { series, instances } = generateHeatmapData(); + +export default function () { + const highcharts = useHighcharts({ heatmap: true }); + + return ( + + + + ); +} diff --git a/pages/common/use-highcharts.ts b/pages/common/use-highcharts.ts index d665197c..2f0bb0dd 100644 --- a/pages/common/use-highcharts.ts +++ b/pages/common/use-highcharts.ts @@ -11,7 +11,8 @@ export function useHighcharts({ xrange = false, solidgauge = false, boost = false, -}: { more?: boolean; xrange?: boolean; solidgauge?: boolean; boost?: boolean } = {}) { + heatmap = false, +}: { more?: boolean; xrange?: boolean; solidgauge?: boolean; boost?: boolean; heatmap?: boolean } = {}) { const [highcharts, setHighcharts] = useState(null); useEffect(() => { @@ -33,6 +34,9 @@ export function useHighcharts({ if (boost) { await import("highcharts/modules/boost"); } + if (heatmap) { + await import("highcharts/modules/heatmap"); + } if (isDevelopment) { await import("highcharts/modules/debugger"); @@ -42,7 +46,7 @@ export function useHighcharts({ }; load(); - }, [more, xrange, solidgauge, boost]); + }, [more, xrange, solidgauge, boost, heatmap]); return highcharts; } diff --git a/src/core/chart-api/chart-extra-tooltip.tsx b/src/core/chart-api/chart-extra-tooltip.tsx index dedaed34..d9c8cce2 100644 --- a/src/core/chart-api/chart-extra-tooltip.tsx +++ b/src/core/chart-api/chart-extra-tooltip.tsx @@ -149,8 +149,10 @@ export class ChartExtraTooltip extends AsyncStore { const pointRect = point ? getPointRect(point) : getGroupRect(group.slice(0, 1)); const groupRect = getGroupRect(group); // The cursor is not shown when column series are present (a UX decision). - const hasColumnSeries = getChartSeries(this.context.chart()).some((s) => s.type === "column"); - this.cursor.create(groupRect, point, group, !hasColumnSeries); + const hideCursorLine = getChartSeries(this.context.chart()).some( + (s) => s.type === "column" || s.type === "heatmap", + ); + this.cursor.create(groupRect, point, group, !hideCursorLine); this.targetTrack.rect(this.context.chart().renderer, { ...pointRect, ...this.commonTrackAttrs }); this.groupTrack.rect(this.context.chart().renderer, { ...groupRect, ...this.commonTrackAttrs }); }; @@ -238,7 +240,8 @@ class HighlightCursorCartesian { isPointVisible(point) && !isXThreshold(point.series) && point.series.type !== "column" && - point.series.type !== "errorbar" + point.series.type !== "errorbar" && + point.series.type !== "heatmap" ); }; }