//
//     Copyright © 2011-2025 Cambridge Intelligence Limited.
//     All rights reserved.
//
//     Sample Code
//
//!    Use multiple time bars to explore data.
import KeyLines from "keylines";
import { data } from "./overview-data.js";

let chart;
let timebar;
let timebar2;

const histogramOptions = {
  colour: "#88A6AF",
  highlightColour: "#C6524C",
};
const selectionColour = "#E2A899";

// we'll use this flag to prevent self-update changes
// from one bar to another
let isUpdating = false;
async function afterLoading() {
  await chart.layout("organic", {});
  // set initial sliders narrowed to November 2010
  timebar2.range(new Date(2010, 10, 1), new Date(2010, 11, 1), {
    animate: true,
  });
}

async function setChartRange(filterFunc) {
  await chart.filter(filterFunc, { animate: false, type: "link" });
  chart.layout("organic", { mode: "adaptive", animate: true, time: 1000 });
}

function unlockSync() {
  // We need to call it async to make it work smoothly
  setTimeout(() => {
    isUpdating = false;
  }, 20);
}
const setRanges = (origin, other) => async () => {
  if (!isUpdating) {
    isUpdating = true;
    const range = await origin.range();
    await other.range(range.dt1, range.dt2, { animate: true });
    unlockSync();
    setChartRange(origin.inRange);
  }
};

function doSelection() {
  let selection = chart.selection();
  if (selection.length > 0) {
    const neighbours = chart.graph().neighbours(selection);
    selection = selection.concat(neighbours.links);
    selection = { id: selection, c: selectionColour };
  }
  timebar.selection(selection);
  timebar2.selection(selection);
}

async function klReady(ready) {
  chart = ready[0];
  timebar = ready[1];
  timebar2 = ready[2];

  // 1. Attach the Events before loading the data

  // Sync timebars together
  timebar.on("change", setRanges(timebar, timebar2));
  timebar2.on("change", setRanges(timebar2, timebar));

  // Tell the chart to communicate the selection to the timebars
  chart.on("selection-change", doSelection);

  // 2. Now load the data

  // Be carefull when you load the data:
  // it is an expensive task, expecially with big datasets
  await timebar2.load(data);
  await timebar.load(data);
  // Load, layout and raise the flag
  await chart.load(data);
  afterLoading();
}

$(() => {
  const chartOptions = {
    logo: { u: "/images/Logo.png" },
    selectionColour,
    overview: { shown: false, icon: false },
  };
  const overviewOptions = {
    sliders: "free",
    histogram: histogramOptions,
    playSpeed: 20,
  };
  const detailOptions = {
    histogram: histogramOptions,
    showControlBar: false,
    scale: { showMinor: true, showMajor: false },
    sliders: "none",
  };

  KeyLines.create([
    { container: "klchart", type: "chart", options: chartOptions },
    { container: "kltimebar1", type: "timebar", options: detailOptions },
    { container: "kltimebar2", type: "timebar", options: overviewOptions },
  ]).then(klReady);
});
<!DOCTYPE html>
<html lang="en" style="background-color: #2d383f;">
  <head>
    <meta charset="UTF-8">
    <title>Multiple Time Bars</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">
    <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="/overview.js" crossorigin="use-credentials" 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" id="klchart" style="height: calc(100% - 292px);"></div>
          <div class="kltimebar" id="kltimebar1" style="height:151px;"></div>
          <div class="kltimebar" id="kltimebar2" style="height:141px;"></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%;">Multiple Time Bars</text>
          </svg>
        </div>
        <div class="tab-content-panel" data-tab-group="rhs">
          <div class="toggle-content is-visible tabcontent" id="controlsTab">
            <form autocomplete="off" onsubmit="return false" id="rhsForm">
              <div class="cicontent">
                <p>
                  Multiple time bars set at different scales and interacting with each other, using 
                  Nodobo phone call data.
                </p>
                <fieldset>
                  <legend>Interaction</legend>
                  <p>The top time bar uses standard features (panning/zooming) and the date range changes. Sliders have been disabled.</p>
                  <p>The bottom time bar is locked to a fitted scale, the sliders can be moved to control the date range.</p>
                  <p>Both time bars and the chart are all linked together and changing the date range on one time bar effects every other component.</p>
                  <p>Selecting nodes on the chart will show that selection on both time bars.</p>
                </fieldset>
                <fieldset> 
                  <legend>Data Format</legend>
                  <p>
                     The time bar data format 
                    is similar to that used for the chart. It is possible to pass the same data object to both components.
                  </p>
                </fieldset>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
    <div id="moreParent">
      <div id="moreContainer">
      </div>
    </div>
    <div id="lazyScripts">
    </div>
  </body>
</html>
Loading source