//
//     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