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