Move the cursor over the time series chart to display a tooltip with additional information.
The pointer-move event is triggered by moving the cursor over the time series chart.
See Also
Move the cursor over the time series chart to display a tooltip with additional information.
The onTimelinePointerMove event is triggered by moving the cursor over the time series chart.
See Also
import { createTimeline } from "kronograph";
import data from "./data";
const timelineElement = document.getElementById("my-timeline");
const tooltipElement = document.getElementById("my-tooltip");
const labelElement = document.getElementById("tooltip-label");
const valueElement = document.getElementById("tooltip-value");
const timeElement = document.getElementById("tooltip-time");
const timeline = createTimeline("my-timeline");
let allowTooltip = true;
function showTooltip(x, y, chartId, value, time) {
const bounds = timelineElement.getBoundingClientRect();
// reveal the hidden tooltip element
tooltipElement.style.display = "block";
const chartColor = data.timeSeriesCharts[chartId].color;
// add a left border to the tooltip, matching the chart color
tooltipElement.style["border-left"] = `solid 4px ${chartColor}`;
const left = bounds.left + x;
const top = bounds.top + y;
// position the tooltip, with a horizontal offset of 10px from the data point
tooltipElement.style.left = `${left + 10}px`;
tooltipElement.style.top = `${top}px`;
labelElement.innerText = chartId;
valueElement.innerText = `${value} Mb/s`;
timeElement.innerText = time;
}
function hideTooltip() {
tooltipElement.style.display = "none";
}
function handlePointerMove({ targetType, subItem }) {
if (allowTooltip && targetType === "timeSeriesChart" && subItem) {
const { subId, x, y, value, time } = subItem;
const label = subId.split("-")[0];
const timeString = time.toLocaleTimeString([], { hour12: true });
showTooltip(x, y, label, value, timeString);
} else {
hideTooltip();
}
}
function handleDragStart() {
// disable tooltips while dragging
hideTooltip();
allowTooltip = false;
}
function handleDragEnd() {
allowTooltip = true;
}
timeline.options({ timeSeriesCharts: { sizePercent: 100 } });
timeline.on("pointer-move", handlePointerMove);
timeline.on("drag-start", handleDragStart);
timeline.on("drag-end", handleDragEnd);
timeline.set(data);
timeline.fit(); export default {
entities: {},
events: {},
timeSeriesCharts: {
Client: {
color: "#ff8838",
fillAreaAlpha: 0.05,
data: [
{ time: Date.UTC(2021, 7, 19, 11, 31, 15, 131), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 31, 21, 796), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 31, 41, 960), value: 27 },
{ time: Date.UTC(2021, 7, 19, 11, 32, 5, 809), value: 25 },
{ time: Date.UTC(2021, 7, 19, 11, 32, 39, 572), value: 27.5 },
{ time: Date.UTC(2021, 7, 19, 11, 33, 35, 459), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 34, 15, 89), value: 27 },
{ time: Date.UTC(2021, 7, 19, 11, 35, 20, 345), value: 26 },
{ time: Date.UTC(2021, 7, 19, 11, 36, 6, 112), value: 23 },
{ time: Date.UTC(2021, 7, 19, 11, 36, 36, 298), value: 22 },
{ time: Date.UTC(2021, 7, 19, 11, 37, 6, 503), value: 24 },
{ time: Date.UTC(2021, 7, 19, 11, 38, 13, 819), value: 24.5 },
{ time: Date.UTC(2021, 7, 19, 11, 38, 30, 447), value: 24 },
{ time: Date.UTC(2021, 7, 19, 11, 38, 32, 501), value: 23.5 },
{ time: Date.UTC(2021, 7, 19, 11, 38, 42, 325), value: 23 },
{ time: Date.UTC(2021, 7, 19, 11, 38, 54, 240), value: 23 },
{ time: Date.UTC(2021, 7, 19, 11, 38, 57, 553), value: 22 },
{ time: Date.UTC(2021, 7, 19, 11, 39, 0, 815), value: 22 },
{ time: Date.UTC(2021, 7, 19, 11, 39, 43, 424), value: 21.5 },
{ time: Date.UTC(2021, 7, 19, 11, 40, 42, 803), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 41, 1, 835), value: 27 },
{ time: Date.UTC(2021, 7, 19, 11, 41, 32, 78), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 41, 44, 447), value: 28.5 },
{ time: Date.UTC(2021, 7, 19, 11, 41, 49, 421), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 41, 49, 589), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 42, 33, 664), value: 27 },
{ time: Date.UTC(2021, 7, 19, 11, 42, 47, 674), value: 26.5 },
{ time: Date.UTC(2021, 7, 19, 11, 43, 12, 81), value: 25 },
{ time: Date.UTC(2021, 7, 19, 11, 43, 22, 184), value: 24.8 },
{ time: Date.UTC(2021, 7, 19, 11, 43, 47, 921), value: 23 },
{ time: Date.UTC(2021, 7, 19, 11, 44, 45, 503), value: 24 },
{ time: Date.UTC(2021, 7, 19, 11, 45, 6, 794), value: 23 },
{ time: Date.UTC(2021, 7, 19, 11, 45, 14, 358), value: 22.5 },
{ time: Date.UTC(2021, 7, 19, 11, 45, 27, 572), value: 21 },
{ time: Date.UTC(2021, 7, 19, 11, 45, 40, 573), value: 21 },
{ time: Date.UTC(2021, 7, 19, 11, 46, 3, 266), value: 20.5 },
{ time: Date.UTC(2021, 7, 19, 11, 46, 6, 218), value: 20.5 },
{ time: Date.UTC(2021, 7, 19, 11, 47, 12, 758), value: 19.5 },
{ time: Date.UTC(2021, 7, 19, 11, 47, 40, 451), value: 20 },
{ time: Date.UTC(2021, 7, 19, 11, 47, 51, 302), value: 21 },
{ time: Date.UTC(2021, 7, 19, 11, 48, 9, 30), value: 20 },
{ time: Date.UTC(2021, 7, 19, 11, 48, 19, 825), value: 22 },
{ time: Date.UTC(2021, 7, 19, 11, 48, 31, 184), value: 21 },
{ time: Date.UTC(2021, 7, 19, 11, 48, 56, 779), value: 22 },
{ time: Date.UTC(2021, 7, 19, 11, 49, 23, 739), value: 22.5 },
{ time: Date.UTC(2021, 7, 19, 11, 50, 6, 565), value: 21 },
{ time: Date.UTC(2021, 7, 19, 11, 50, 14, 735), value: 23 },
{ time: Date.UTC(2021, 7, 19, 11, 51, 53, 182), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 52, 50, 716), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 53, 16, 5), value: 27 },
{ time: Date.UTC(2021, 7, 19, 11, 53, 17, 509), value: 26.5 },
{ time: Date.UTC(2021, 7, 19, 11, 53, 37, 194), value: 27.5 },
{ time: Date.UTC(2021, 7, 19, 11, 54, 8, 968), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 54, 47, 269), value: 27 },
],
},
Server: {
color: "#40E0D0",
fillAreaAlpha: 0.05,
data: [
{
time: 1629372675131,
value: 22,
},
{
time: 1629372681796,
value: 21,
},
{
time: 1629372701960,
value: 23,
},
{
time: 1629372725809,
value: 19,
},
{
time: 1629372759572,
value: 23,
},
{
time: 1629372815459,
value: 23,
},
{
time: 1629372855089,
value: 20,
},
{
time: 1629372920345,
value: 23,
},
{
time: 1629372966112,
value: 18,
},
{
time: 1629372996298,
value: 15,
},
{
time: 1629373026503,
value: 17,
},
{
time: 1629373093819,
value: 18,
},
{
time: 1629373110447,
value: 18,
},
{
time: 1629373112501,
value: 19,
},
{
time: 1629373122325,
value: 17,
},
{
time: 1629373134240,
value: 18,
},
{
time: 1629373137553,
value: 16,
},
{
time: 1629373140815,
value: 15,
},
{
time: 1629373183424,
value: 18,
},
{
time: 1629373242803,
value: 22,
},
{
time: 1629373261835,
value: 20,
},
{
time: 1629373292078,
value: 23,
},
{
time: 1629373304447,
value: 25,
},
{
time: 1629373309421,
value: 24,
},
{
time: 1629373309589,
value: 21,
},
{
time: 1629373353664,
value: 23,
},
{
time: 1629373367674,
value: 22,
},
{
time: 1629373392081,
value: 18,
},
{
time: 1629373402184,
value: 21,
},
{
time: 1629373427921,
value: 17,
},
{
time: 1629373485503,
value: 18,
},
{
time: 1629373506794,
value: 19,
},
{
time: 1629373514358,
value: 18,
},
{
time: 1629373527572,
value: 15,
},
{
time: 1629373540573,
value: 18,
},
{
time: 1629373563266,
value: 17,
},
{
time: 1629373566218,
value: 15,
},
{
time: 1629373632758,
value: 12,
},
{
time: 1629373660451,
value: 14,
},
{
time: 1629373671302,
value: 17,
},
{
time: 1629373689030,
value: 12,
},
{
time: 1629373699825,
value: 14,
},
{
time: 1629373711184,
value: 14,
},
{
time: 1629373736779,
value: 19,
},
{
time: 1629373763739,
value: 19,
},
{
time: 1629373806565,
value: 16,
},
{
time: 1629373814735,
value: 17,
},
{
time: 1629373913182,
value: 24,
},
{
time: 1629373970716,
value: 22,
},
{
time: 1629373996005,
value: 19,
},
{
time: 1629373997509,
value: 21,
},
{
time: 1629374017194,
value: 23,
},
{
time: 1629374048968,
value: 23,
},
{
time: 1629374087269,
value: 22,
},
],
},
},
timeSeriesChartStacks: {
networkPerformance: {
chartIds: ["Client", "Server"],
label: "Network Performance",
},
},
}; <!doctype html>
<html>
<head>
<link rel="stylesheet" href="@ci/theme/kg/css/examples.css" />
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div class="story">
<div class="story__timeline" id="my-timeline"></div>
<div id="my-tooltip" class="story__timeSeriesChartsTooltip stack stack--small">
<div class="story__timeSeriesChartsTooltip__label" id="tooltip-label"></div>
<div class="story__timeSeriesChartsTooltip__wrapper">
<div class="story__timeSeriesChartsTooltip__value" id="tooltip-value"></div>
<div class="story__timeSeriesChartsTooltip__time" id="tooltip-time"></div>
</div>
</div>
</div>
<script type="module" src="./code.js"></script>
</body>
</html> @import url("https://fonts.googleapis.com/css?family=Muli:200,400,500,700&display=swap");
body {
font-family: "Muli", "Helvetica Neue", Helvetica, sans-serif;
font-weight: 400;
margin: 0;
}
.story {
background-color: hsl(210, 18%, 22%); /* Charcoal */
color: hsl(214, 15%, 91%);
display: flex;
flex-direction: column;
height: 100vh;
}
.story__timeline {
flex: 2;
min-height: 0px; /* Allow the DOM to resize the timeline */
}
.stack > * {
margin-bottom: 0;
margin-top: 0;
}
.stack > * + * {
margin-top: 0.2rem;
}
.story__timeSeriesChartsTooltip {
background-color: hsl(209, 15%, 28%);
border-radius: 0.1975rem;
color: hsl(216, 33%, 97%);
display: none;
overflow-y: auto;
padding: 0.3rem;
position: absolute;
pointer-events: none;
}
.story__timeSeriesChartsTooltip__wrapper {
display: flex;
flex-direction: row;
justify-content: space-between;
min-width: 160px;
}
.story__timeSeriesChartsTooltip__label {
color: hsl(214, 15%, 91%);
font-size: 0.8em;
font-weight: bold;
}
.story__timeSeriesChartsTooltip__value {
color: hsl(214, 15%, 91%);
font-size: 0.8em;
}
.story__timeSeriesChartsTooltip__time {
color: hsl(211, 13%, 65%);
font-size: 0.7em;
} import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import Timeline from "kronograph/react/Timeline";
import data from "./data";
export const Demo = () => {
const [tooltip, setTooltip] = useState(null);
const [allowTooltip, setAllowTooltip] = useState(true);
const onPointerMove = ({ targetType, subItem }) => {
if (allowTooltip && targetType === "timeSeriesChart" && subItem) {
const { subId, x, y, value, time } = subItem;
const chartId = subId.split("-")[0];
const chartColor = data.timeSeriesCharts[chartId].color;
const timeString = time.toLocaleTimeString([], { hour12: true });
setTooltip({
label: chartId,
color: chartColor,
value,
time: timeString,
// horizontally offset tooltip slightly from the data point
left: x + 10,
top: y,
});
} else {
setTooltip(null);
}
};
const onDragStart = () => {
// disable tooltips while dragging
setTooltip(null);
setAllowTooltip(false);
};
const onDragEnd = () => {
setAllowTooltip(true);
};
return (
<div className="story">
<Timeline
className="story__timeline"
entities={data.entities}
events={data.events}
timeSeriesCharts={data.timeSeriesCharts}
timeSeriesChartStacks={data.timeSeriesChartStacks}
options={{ timeSeriesCharts: { sizePercent: 100 } }}
onTimelinePointerMove={onPointerMove}
onTimelineDragStart={onDragStart}
onTimelineDragEnd={onDragEnd}
/>
{tooltip (
<div
id="my-tooltip"
className="story__timeSeriesChartsTooltip stack stack--small"
style={{
display: "block",
left: tooltip.left,
top: tooltip.top,
borderLeft: `4px solid ${tooltip.color}`,
}}
>
<div className="story__timeSeriesChartsTooltip__label" id="tooltip-label">
{tooltip.label}
</div>
<div className="story__timeSeriesChartsTooltip__wrapper">
<div className="story__timeSeriesChartsTooltip__value" id="tooltip-value">
{tooltip.value} Mb/s
</div>
<div className="story__timeSeriesChartsTooltip__time" id="tooltip-time">
{tooltip.time}
</div>
</div>
</div>
) : null}
</div>
);
};
const root = createRoot(document.getElementById("my-timeline"));
root.render(<Demo />); export default {
entities: {},
events: {},
timeSeriesCharts: {
Client: {
color: "#ff8838",
fillAreaAlpha: 0.05,
data: [
{ time: Date.UTC(2021, 7, 19, 11, 31, 15, 131), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 31, 21, 796), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 31, 41, 960), value: 27 },
{ time: Date.UTC(2021, 7, 19, 11, 32, 5, 809), value: 25 },
{ time: Date.UTC(2021, 7, 19, 11, 32, 39, 572), value: 27.5 },
{ time: Date.UTC(2021, 7, 19, 11, 33, 35, 459), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 34, 15, 89), value: 27 },
{ time: Date.UTC(2021, 7, 19, 11, 35, 20, 345), value: 26 },
{ time: Date.UTC(2021, 7, 19, 11, 36, 6, 112), value: 23 },
{ time: Date.UTC(2021, 7, 19, 11, 36, 36, 298), value: 22 },
{ time: Date.UTC(2021, 7, 19, 11, 37, 6, 503), value: 24 },
{ time: Date.UTC(2021, 7, 19, 11, 38, 13, 819), value: 24.5 },
{ time: Date.UTC(2021, 7, 19, 11, 38, 30, 447), value: 24 },
{ time: Date.UTC(2021, 7, 19, 11, 38, 32, 501), value: 23.5 },
{ time: Date.UTC(2021, 7, 19, 11, 38, 42, 325), value: 23 },
{ time: Date.UTC(2021, 7, 19, 11, 38, 54, 240), value: 23 },
{ time: Date.UTC(2021, 7, 19, 11, 38, 57, 553), value: 22 },
{ time: Date.UTC(2021, 7, 19, 11, 39, 0, 815), value: 22 },
{ time: Date.UTC(2021, 7, 19, 11, 39, 43, 424), value: 21.5 },
{ time: Date.UTC(2021, 7, 19, 11, 40, 42, 803), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 41, 1, 835), value: 27 },
{ time: Date.UTC(2021, 7, 19, 11, 41, 32, 78), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 41, 44, 447), value: 28.5 },
{ time: Date.UTC(2021, 7, 19, 11, 41, 49, 421), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 41, 49, 589), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 42, 33, 664), value: 27 },
{ time: Date.UTC(2021, 7, 19, 11, 42, 47, 674), value: 26.5 },
{ time: Date.UTC(2021, 7, 19, 11, 43, 12, 81), value: 25 },
{ time: Date.UTC(2021, 7, 19, 11, 43, 22, 184), value: 24.8 },
{ time: Date.UTC(2021, 7, 19, 11, 43, 47, 921), value: 23 },
{ time: Date.UTC(2021, 7, 19, 11, 44, 45, 503), value: 24 },
{ time: Date.UTC(2021, 7, 19, 11, 45, 6, 794), value: 23 },
{ time: Date.UTC(2021, 7, 19, 11, 45, 14, 358), value: 22.5 },
{ time: Date.UTC(2021, 7, 19, 11, 45, 27, 572), value: 21 },
{ time: Date.UTC(2021, 7, 19, 11, 45, 40, 573), value: 21 },
{ time: Date.UTC(2021, 7, 19, 11, 46, 3, 266), value: 20.5 },
{ time: Date.UTC(2021, 7, 19, 11, 46, 6, 218), value: 20.5 },
{ time: Date.UTC(2021, 7, 19, 11, 47, 12, 758), value: 19.5 },
{ time: Date.UTC(2021, 7, 19, 11, 47, 40, 451), value: 20 },
{ time: Date.UTC(2021, 7, 19, 11, 47, 51, 302), value: 21 },
{ time: Date.UTC(2021, 7, 19, 11, 48, 9, 30), value: 20 },
{ time: Date.UTC(2021, 7, 19, 11, 48, 19, 825), value: 22 },
{ time: Date.UTC(2021, 7, 19, 11, 48, 31, 184), value: 21 },
{ time: Date.UTC(2021, 7, 19, 11, 48, 56, 779), value: 22 },
{ time: Date.UTC(2021, 7, 19, 11, 49, 23, 739), value: 22.5 },
{ time: Date.UTC(2021, 7, 19, 11, 50, 6, 565), value: 21 },
{ time: Date.UTC(2021, 7, 19, 11, 50, 14, 735), value: 23 },
{ time: Date.UTC(2021, 7, 19, 11, 51, 53, 182), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 52, 50, 716), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 53, 16, 5), value: 27 },
{ time: Date.UTC(2021, 7, 19, 11, 53, 17, 509), value: 26.5 },
{ time: Date.UTC(2021, 7, 19, 11, 53, 37, 194), value: 27.5 },
{ time: Date.UTC(2021, 7, 19, 11, 54, 8, 968), value: 28 },
{ time: Date.UTC(2021, 7, 19, 11, 54, 47, 269), value: 27 },
],
},
Server: {
color: "#40E0D0",
fillAreaAlpha: 0.05,
data: [
{
time: 1629372675131,
value: 22,
},
{
time: 1629372681796,
value: 21,
},
{
time: 1629372701960,
value: 23,
},
{
time: 1629372725809,
value: 19,
},
{
time: 1629372759572,
value: 23,
},
{
time: 1629372815459,
value: 23,
},
{
time: 1629372855089,
value: 20,
},
{
time: 1629372920345,
value: 23,
},
{
time: 1629372966112,
value: 18,
},
{
time: 1629372996298,
value: 15,
},
{
time: 1629373026503,
value: 17,
},
{
time: 1629373093819,
value: 18,
},
{
time: 1629373110447,
value: 18,
},
{
time: 1629373112501,
value: 19,
},
{
time: 1629373122325,
value: 17,
},
{
time: 1629373134240,
value: 18,
},
{
time: 1629373137553,
value: 16,
},
{
time: 1629373140815,
value: 15,
},
{
time: 1629373183424,
value: 18,
},
{
time: 1629373242803,
value: 22,
},
{
time: 1629373261835,
value: 20,
},
{
time: 1629373292078,
value: 23,
},
{
time: 1629373304447,
value: 25,
},
{
time: 1629373309421,
value: 24,
},
{
time: 1629373309589,
value: 21,
},
{
time: 1629373353664,
value: 23,
},
{
time: 1629373367674,
value: 22,
},
{
time: 1629373392081,
value: 18,
},
{
time: 1629373402184,
value: 21,
},
{
time: 1629373427921,
value: 17,
},
{
time: 1629373485503,
value: 18,
},
{
time: 1629373506794,
value: 19,
},
{
time: 1629373514358,
value: 18,
},
{
time: 1629373527572,
value: 15,
},
{
time: 1629373540573,
value: 18,
},
{
time: 1629373563266,
value: 17,
},
{
time: 1629373566218,
value: 15,
},
{
time: 1629373632758,
value: 12,
},
{
time: 1629373660451,
value: 14,
},
{
time: 1629373671302,
value: 17,
},
{
time: 1629373689030,
value: 12,
},
{
time: 1629373699825,
value: 14,
},
{
time: 1629373711184,
value: 14,
},
{
time: 1629373736779,
value: 19,
},
{
time: 1629373763739,
value: 19,
},
{
time: 1629373806565,
value: 16,
},
{
time: 1629373814735,
value: 17,
},
{
time: 1629373913182,
value: 24,
},
{
time: 1629373970716,
value: 22,
},
{
time: 1629373996005,
value: 19,
},
{
time: 1629373997509,
value: 21,
},
{
time: 1629374017194,
value: 23,
},
{
time: 1629374048968,
value: 23,
},
{
time: 1629374087269,
value: 22,
},
],
},
},
timeSeriesChartStacks: {
networkPerformance: {
chartIds: ["Client", "Server"],
label: "Network Performance",
},
},
}; <!doctype html>
<html>
<head>
<link rel="stylesheet" href="@ci/theme/kg/css/examples.css" />
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div id="my-timeline" style="height: 100vh"></div>
<script type="module" src="./code.jsx"></script>
</body>
</html> @import url("https://fonts.googleapis.com/css?family=Muli:200,400,500,700&display=swap");
body {
font-family: "Muli", "Helvetica Neue", Helvetica, sans-serif;
font-weight: 400;
margin: 0;
}
.story {
background-color: hsl(210, 18%, 22%); /* Charcoal */
color: hsl(214, 15%, 91%);
display: flex;
flex-direction: column;
height: 100vh;
}
.story__timeline {
flex: 2;
min-height: 0px; /* Allow the DOM to resize the timeline */
}
.stack > * {
margin-bottom: 0;
margin-top: 0;
}
.stack > * + * {
margin-top: 0.2rem;
}
.story__timeSeriesChartsTooltip {
background-color: hsl(209, 15%, 28%);
border-radius: 0.1975rem;
color: hsl(216, 33%, 97%);
display: none;
overflow-y: auto;
padding: 0.3rem;
position: absolute;
pointer-events: none;
}
.story__timeSeriesChartsTooltip__wrapper {
display: flex;
flex-direction: row;
justify-content: space-between;
min-width: 160px;
}
.story__timeSeriesChartsTooltip__label {
color: hsl(214, 15%, 91%);
font-size: 0.8em;
font-weight: bold;
}
.story__timeSeriesChartsTooltip__value {
color: hsl(214, 15%, 91%);
font-size: 0.8em;
}
.story__timeSeriesChartsTooltip__time {
color: hsl(211, 13%, 65%);
font-size: 0.7em;
}