//
// Copyright © 2011-2025 Cambridge Intelligence Limited.
// All rights reserved.
//
// Sample Code
//
//! Animate link widths to visualise the volume of data in the time bar.
import KeyLines from "keylines";
import data from "./animatelinkwidth-data.js";
let chart;
let timebar;
const MAX_LINK_WIDTH = 10;
const resetButton = document.getElementById("reset");
const startStopButton = document.getElementById("start-stop");
function scaleLinks() {
const widthList = [];
let maxWidth = -1;
// get the current range and parse it to a timestamp
const timeRange = timebar.range();
const itemsInRange = timebar.getIds(timeRange.dt1, timeRange.dt2);
itemsInRange.forEach((id) => {
const item = chart.getItem(id);
// calculate the number of times each connection occured in the current range
if (item && item.type === "link") {
let width = 0;
item.dt.forEach((time) => {
if (time >= timeRange.dt1 && time <= timeRange.dt2) {
width += 1;
}
});
maxWidth = Math.max(maxWidth, width);
widthList.push({ id, w: width });
}
});
// scale all widths relative to widest link
widthList.forEach((item) => {
item.w = (MAX_LINK_WIDTH * item.w) / maxWidth;
});
chart.animateProperties(widthList, { time: 100 });
}
function reset() {
timebar.pause();
timebar.range(new Date(2000, 0), new Date(2000, 1), { animate: false });
}
function startStop() {
if (startStopButton.innerHTML === "Play") {
timebar.play();
} else {
timebar.pause();
}
}
async function klReady() {
// load the data (defined in separate js file) into both the chart and time bar
timebar.load(data);
reset();
chart.load(data);
await chart.filter(timebar.inRange, { animate: false, type: "link" });
scaleLinks();
chart.layout("organic");
// When the time bar range changes
timebar.on("change", async () => {
scaleLinks();
// filter the chart to show only items in the new range
await chart.filter(timebar.inRange, { animate: false, type: "link" });
chart.layout("organic", {
mode: "adaptive",
time: 500,
fixed: ["14", "15"],
});
});
timebar.on("end", timebar.pause);
timebar.on("play", () => {
startStopButton.innerHTML = "Pause";
});
timebar.on("pause", () => {
startStopButton.innerHTML = "Play";
});
resetButton.addEventListener("click", reset);
startStopButton.addEventListener("click", startStop);
}
async function loadKeyLines() {
await document.fonts.load('24px "Font Awesome 5 Free"');
const options = {
logo: "/images/Logo.png",
handMode: true,
overview: { icon: false, shown: false },
iconFontFamily: "Font Awesome 5 Free",
};
[chart, timebar] = await KeyLines.create([
{ container: "klchart", options },
{ container: "kltimebar", type: "timebar" },
]);
klReady();
}
window.addEventListener("DOMContentLoaded", loadKeyLines);
<!DOCTYPE html>
<html lang="en" style="background-color: #2d383f;">
<head>
<meta charset="UTF-8">
<title>Animate Link Widths</title>
<link rel="stylesheet" type="text/css" href="/css/keylines.css">
<link rel="stylesheet" type="text/css" href="/css/minimalsdk.css">
<link rel="stylesheet" type="text/css" href="/css/sdk-layout.css">
<link rel="stylesheet" type="text/css" href="/css/demo.css">
<link rel="stylesheet" type="text/css" href="/css/fontawesome5/fontawesome.css">
<link rel="stylesheet" type="text/css" href="/css/fontawesome5/solid.css">
<script src="/vendor/jquery.js" defer type="text/javascript"></script>
<script id="keylines" src="/public/keylines.umd.cjs" defer type="text/javascript"></script>
<script src="/animatelinkwidth.js" crossorigin="use-credentials" defer type="module"></script>
</head>
<body>
<div class="chart-wrapper demo-cols">
<div class="tab-content-panel flex1" id="lhs" data-tab-group="rhs">
<div class="toggle-content is-visible" id="lhsVisual" style="width:100%; height: 100%;">
<div class="klchart klchart-timebar" id="klchart">
</div>
<div class="kltimebar" id="kltimebar">
</div>
</div>
</div>
<div class="rhs citext closed" id="demorhscontent">
<div class="title-bar">
<svg viewBox="0 0 360 60" style="max-width: 360px; max-height: 60px; font-size: 24px; font-family: Raleway; flex: 1;">
<text x="0" y="38" style="width: 100%;">Animate Link Widths</text>
</svg>
</div>
<div class="tab-content-panel" data-tab-group="rhs">
<div class="toggle-content is-visible tabcontent" id="controlsTab">
<p>Use the time bar controls and the animation buttons below to see link widths change over time depending on call volume.</p>
<form autocomplete="off" onsubmit="return false" id="rhsForm">
<div class="cicontent">
<fieldset> </fieldset>
<legend>Animation</legend>
<p>
<button class="btn" type="button" value="Reset" id="reset">Reset</button>
<button class="btn" type="button" value="Start" id="start-stop">Play</button>
</p>
</div>
</form>
</div>
</div>
</div>
</div>
<div id="moreParent">
<div id="moreContainer">
</div>
</div>
<div id="lazyScripts">
</div>
</body>
</html>
Loading source
