The combination of displaying a chart and a time bar simultaneously gives a user flexibility to switch between interacting with the nodes and links (and seeing their temporal distribution on the time bar) or changing the 'when' by manipulating the time bar and seeing the effect on the chart data.
This demo illustrates KeyLines' flexibility by combining two time bars with a standard chart view.
The top bar is presented without controls and shows a whole month view with granularity of a day.
The bottom bar is presented with full controls and variable sliders. It opens with a selected month to the granularity of weeks. The user is free to zoom in and out in time using the controls on the bottom bar and the top bar will automatically show a more detailed view.
Note that while the top bar has no controls it can still be interacted with – time can be dragged backwards and forwards using the top bar and the bottom bar and chart will display appropriate data.
Data set
McDiarmid, A. (Creator), Irvine, J. (Creator), Bell, S. D. (Creator), Banford, J. (Creator). (Apr 2015). Nodobo mobile phone usage data. CRAWDAD. 10.15783/C7HP4Q
Key functions used:
import KeyLines from "keylines";
import { data } from "./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: "/public/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);
}); export const data = {
type: "LinkChart",
items: [
{
type: "node",
c: "#c0c0c0",
id: "9",
t: "9",
},
{
type: "node",
c: "#c0c0c0",
id: "127",
t: "127",
},
{
type: "node",
c: "#c0c0c0",
id: "129",
t: "129",
},
{
type: "node",
c: "#c0c0c0",
id: "157",
t: "157",
},
{
type: "node",
c: "#c0c0c0",
id: "192",
t: "192",
},
{
type: "node",
c: "#c0c0c0",
id: "193",
t: "193",
},
{
type: "node",
c: "#c0c0c0",
id: "208",
t: "208",
},
{
type: "node",
c: "#c0c0c0",
id: "244",
t: "244",
},
{
type: "node",
c: "#c0c0c0",
id: "372",
t: "372",
},
{
type: "node",
c: "#c0c0c0",
id: "452",
t: "452",
},
{
type: "node",
c: "#c0c0c0",
id: "455",
t: "455",
},
{
type: "node",
c: "#c0c0c0",
id: "563",
t: "563",
},
{
type: "node",
c: "#c0c0c0",
id: "901",
t: "901",
},
{
type: "node",
c: "#c0c0c0",
id: "908",
t: "908",
},
{
type: "node",
c: "#c0c0c0",
id: "1641",
t: "1641",
},
{
type: "node",
c: "#c0c0c0",
id: "1740",
t: "1740",
},
{
type: "node",
c: "#c0c0c0",
id: "2172",
t: "2172",
},
{
type: "node",
c: "#c0c0c0",
id: "2327",
t: "2327",
},
{
type: "node",
c: "#c0c0c0",
id: "2330",
t: "2330",
},
{
type: "node",
c: "#c0c0c0",
id: "2367",
t: "2367",
},
{
type: "node",
c: "#c0c0c0",
id: "2432",
t: "2432",
},
{
type: "node",
c: "#c0c0c0",
id: "14099",
t: "14099",
},
{
type: "node",
c: "#c0c0c0",
id: "21261",
t: "21261",
},
{
type: "node",
c: "#c0c0c0",
id: "45347",
t: "45347",
},
{
type: "node",
c: "#c0c0c0",
id: "2284122",
t: "2284122",
},
{
type: "node",
c: "#c0c0c0",
id: "3305122",
t: "3305122",
},
{
type: "node",
c: "#c0c0c0",
id: "3360769",
t: "3360769",
},
{
type: "node",
c: "#c0c0c0",
id: "3371982",
t: "3371982",
},
{
type: "node",
c: "#c0c0c0",
id: "3396625",
t: "3396625",
},
{
type: "node",
c: "#c0c0c0",
id: "5505813",
t: "5505813",
},
{
type: "node",
c: "#c0c0c0",
id: "5844903",
t: "5844903",
},
{
type: "node",
c: "#c0c0c0",
id: "7792837",
t: "7792837",
},
{
type: "node",
c: "#c0c0c0",
id: "8489720",
t: "8489720",
},
{
type: "node",
c: "#c0c0c0",
id: "22400894",
t: "22400894",
},
{
type: "node",
c: "#c0c0c0",
id: "07434677419",
t: "07434677419",
},
{
type: "node",
c: "#c0c0c0",
id: "07610039694",
t: "07610039694",
},
{
type: "node",
c: "#c0c0c0",
id: "07588304495",
t: "07588304495",
},
{
type: "node",
c: "#c0c0c0",
id: "07641036117",
t: "07641036117",
},
{
type: "node",
c: "#c0c0c0",
id: "07981267897",
t: "07981267897",
},
{
type: "node",
c: "#c0c0c0",
id: "07784425582",
t: "07784425582",
},
{
type: "node",
c: "#c0c0c0",
id: "07743039441",
t: "07743039441",
},
{
type: "node",
c: "#c0c0c0",
id: "07163185791",
t: "07163185791",
},
{
type: "node",
c: "#c0c0c0",
id: "01850897526",
t: "01850897526",
},
{
type: "node",
c: "#c0c0c0",
id: "07066875066",
t: "07066875066",
},
{
type: "node",
c: "#c0c0c0",
id: "07691640598",
t: "07691640598",
},
{
type: "node",
c: "#c0c0c0",
id: "07187432175",
t: "07187432175",
},
{
type: "node",
c: "#c0c0c0",
id: "07230262224",
t: "07230262224",
},
{
type: "node",
c: "#c0c0c0",
id: "07110730864",
t: "07110730864",
},
{
type: "node",
c: "#c0c0c0",
id: "07209670163",
t: "07209670163",
},
{
type: "node",
c: "#c0c0c0",
id: "48772130600436761996023412922286",
t: "48772130600436761996023412922286",
},
{
type: "node",
c: "#c0c0c0",
id: "07501874156",
t: "07501874156",
},
{
type: "node",
c: "#c0c0c0",
id: "07681546436",
t: "07681546436",
},
{
type: "node",
c: "#c0c0c0",
id: "07914559382",
t: "07914559382",
},
{
type: "node",
c: "#c0c0c0",
id: "07304637408",
t: "07304637408",
},
{
type: "node",
c: "#c0c0c0",
id: "07087748678",
t: "07087748678",
},
{
type: "node",
c: "#c0c0c0",
id: "07211022593",
t: "07211022593",
},
{
type: "node",
c: "#c0c0c0",
id: "01256721926",
t: "01256721926",
},
{
type: "node",
c: "#c0c0c0",
id: "07607124303",
t: "07607124303",
},
{
type: "node",
c: "#c0c0c0",
id: "07029691700",
t: "07029691700",
},
{
type: "node",
c: "#c0c0c0",
id: "07839321359",
t: "07839321359",
},
{
type: "node",
c: "#c0c0c0",
id: "07651268820",
t: "07651268820",
},
{
type: "node",
c: "#c0c0c0",
id: "01499302899",
t: "01499302899",
},
{
type: "node",
c: "#c0c0c0",
id: "07854607195",
t: "07854607195",
},
{
type: "node",
c: "#c0c0c0",
id: "07080329376",
t: "07080329376",
},
{
type: "node",
c: "#c0c0c0",
id: "07167454533",
t: "07167454533",
},
{
type: "node",
c: "#c0c0c0",
id: "07162108686",
t: "07162108686",
},
{
type: "node",
c: "#c0c0c0",
id: "07541486388",
t: "07541486388",
},
{
type: "node",
c: "#c0c0c0",
id: "07195393761",
t: "07195393761",
},
{
type: "node",
c: "#c0c0c0",
id: "01780890590",
t: "01780890590",
},
{
type: "node",
c: "#c0c0c0",
id: "07978424233",
t: "07978424233",
},
{
type: "node",
c: "#c0c0c0",
id: "07946912731",
t: "07946912731",
},
{
type: "node",
c: "#c0c0c0",
id: "07225912655",
t: "07225912655",
},
{
type: "node",
c: "#c0c0c0",
id: "07400578851",
t: "07400578851",
},
{
type: "node",
c: "#c0c0c0",
id: "01546219380",
t: "01546219380",
},
{
type: "node",
c: "#c0c0c0",
id: "07150470306",
t: "07150470306",
},
{
type: "node",
c: "#c0c0c0",
id: "07266516764",
t: "07266516764",
},
{
type: "node",
c: "#c0c0c0",
id: "07652081795",
t: "07652081795",
},
{
type: "node",
c: "#c0c0c0",
id: "07817341678",
t: "07817341678",
},
{
type: "node",
c: "#c0c0c0",
id: "07869748073",
t: "07869748073",
},
{
type: "node",
c: "#c0c0c0",
id: "07279151148",
t: "07279151148",
},
{
type: "node",
c: "#c0c0c0",
id: "07613917675",
t: "07613917675",
},
{
type: "node",
c: "#c0c0c0",
id: "07771486427",
t: "07771486427",
},
{
type: "node",
c: "#c0c0c0",
id: "07587572122",
t: "07587572122",
},
{
type: "node",
c: "#c0c0c0",
id: "6061629169",
t: "6061629169",
},
{
type: "node",
c: "#c0c0c0",
id: "07758045718",
t: "07758045718",
},
{
type: "node",
c: "#c0c0c0",
id: "07394508492",
t: "07394508492",
},
{
type: "node",
c: "#c0c0c0",
id: "01887771702",
t: "01887771702",
},
{
type: "node",
c: "#c0c0c0",
id: "07806391587",
t: "07806391587",
},
{
type: "node",
c: "#c0c0c0",
id: "07909763438",
t: "07909763438",
},
{
type: "node",
c: "#c0c0c0",
id: "07028004429",
t: "07028004429",
},
{
type: "node",
c: "#c0c0c0",
id: "07392737002",
t: "07392737002",
},
{
type: "node",
c: "#c0c0c0",
id: "07942503106",
t: "07942503106",
},
{
type: "node",
c: "#c0c0c0",
id: "07090017672",
t: "07090017672",
},
{
type: "node",
c: "#c0c0c0",
id: "07962175133",
t: "07962175133",
},
{
type: "node",
c: "#c0c0c0",
id: "07651896055",
t: "07651896055",
},
{
type: "node",
c: "#c0c0c0",
id: "01022354521",
t: "01022354521",
},
{
type: "node",
c: "#c0c0c0",
id: "07830667924",
t: "07830667924",
},
{
type: "node",
c: "#c0c0c0",
id: "07574455931",
t: "07574455931",
},
{
type: "node",
c: "#c0c0c0",
id: "01954651441",
t: "01954651441",
},
{
type: "node",
c: "#c0c0c0",
id: "07122915122",
t: "07122915122",
},
{
type: "node",
c: "#c0c0c0",
id: "01815280008",
t: "01815280008",
},
{
type: "node",
c: "#c0c0c0",
id: "07682111000",
t: "07682111000",
},
{
type: "node",
c: "#c0c0c0",
id: "07969251842",
t: "07969251842",
},
{
type: "node",
c: "#c0c0c0",
id: "07221387474",
t: "07221387474",
},
{
type: "node",
c: "#c0c0c0",
id: "07375968743",
t: "07375968743",
},
{
type: "node",
c: "#c0c0c0",
id: "044",
t: "044",
},
{
type: "node",
c: "#c0c0c0",
id: "07151178213",
t: "07151178213",
},
{
type: "node",
c: "#c0c0c0",
id: "07197268544",
t: "07197268544",
},
{
type: "node",
c: "#c0c0c0",
id: "07014881393",
t: "07014881393",
},
{
type: "node",
c: "#c0c0c0",
id: "07246826358",
t: "07246826358",
},
{
type: "node",
c: "#c0c0c0",
id: "07548213987",
t: "07548213987",
},
{
type: "node",
c: "#c0c0c0",
id: "14191086749599",
t: "14191086749599",
},
{
type: "node",
c: "#c0c0c0",
id: "14853692371599",
t: "14853692371599",
},
{
type: "node",
c: "#c0c0c0",
id: "07896182404",
t: "07896182404",
},
{
type: "node",
c: "#c0c0c0",
id: "07118310788",
t: "07118310788",
},
{
type: "node",
c: "#c0c0c0",
id: "07944968233",
t: "07944968233",
},
{
type: "node",
c: "#c0c0c0",
id: "07720520621",
t: "07720520621",
},
{
type: "node",
c: "#c0c0c0",
id: "07775682498",
t: "07775682498",
},
{
type: "node",
c: "#c0c0c0",
id: "07023552017",
t: "07023552017",
},
{
type: "node",
c: "#c0c0c0",
id: "07340142898",
t: "07340142898",
},
{
type: "node",
c: "#c0c0c0",
id: "07634569803",
t: "07634569803",
},
{
type: "node",
c: "#c0c0c0",
id: "01575974486",
t: "01575974486",
},
{
type: "node",
c: "#c0c0c0",
id: "07153234302",
t: "07153234302",
},
{
type: "node",
c: "#c0c0c0",
id: "07633839447",
t: "07633839447",
},
{
type: "node",
c: "#c0c0c0",
id: "07341891255",
t: "07341891255",
},
{
type: "node",
c: "#c0c0c0",
id: "07926168565",
t: "07926168565",
},
{
type: "node",
c: "#c0c0c0",
id: "07873904393",
t: "07873904393",
},
{
type: "node",
c: "#c0c0c0",
id: "07976349200",
t: "07976349200",
},
{
type: "node",
c: "#c0c0c0",
id: "07476886744",
t: "07476886744",
},
{
type: "node",
c: "#c0c0c0",
id: "01527646556",
t: "01527646556",
},
{
type: "node",
c: "#c0c0c0",
id: "07318250386",
t: "07318250386",
},
{
type: "node",
c: "#c0c0c0",
id: "07806980885",
t: "07806980885",
},
{
type: "node",
c: "#c0c0c0",
id: "07514503190",
t: "07514503190",
},
{
type: "node",
c: "#c0c0c0",
id: "07456622368",
t: "07456622368",
},
{
type: "node",
c: "#c0c0c0",
id: "07245763413",
t: "07245763413",
},
{
type: "node",
c: "#c0c0c0",
id: "07676963558",
t: "07676963558",
},
{
type: "node",
c: "#c0c0c0",
id: "07613569456",
t: "07613569456",
},
{
type: "node",
c: "#c0c0c0",
id: "07776253730",
t: "07776253730",
},
{
type: "node",
c: "#c0c0c0",
id: "07102745960",
t: "07102745960",
},
{
type: "node",
c: "#c0c0c0",
id: "07389444649",
t: "07389444649",
},
{
type: "node",
c: "#c0c0c0",
id: "07126482937",
t: "07126482937",
},
{
type: "node",
c: "#c0c0c0",
id: "07966846548",
t: "07966846548",
},
{
type: "node",
c: "#c0c0c0",
id: "07833688765",
t: "07833688765",
},
{
type: "node",
c: "#c0c0c0",
id: "01739521988",
t: "01739521988",
},
{
type: "node",
c: "#c0c0c0",
id: "07585377112",
t: "07585377112",
},
{
type: "node",
c: "#c0c0c0",
id: "07294484859",
t: "07294484859",
},
{
type: "node",
c: "#c0c0c0",
id: "07850316631",
t: "07850316631",
},
{
type: "node",
c: "#c0c0c0",
id: "07520192003",
t: "07520192003",
},
{
type: "node",
c: "#c0c0c0",
id: "07877889057",
t: "07877889057",
},
{
type: "node",
c: "#c0c0c0",
id: "07073084322",
t: "07073084322",
},
{
type: "node",
c: "#c0c0c0",
id: "07492710736",
t: "07492710736",
},
{
type: "node",
c: "#c0c0c0",
id: "07070949771",
t: "07070949771",
},
{
type: "node",
c: "#c0c0c0",
id: "07252637450",
t: "07252637450",
},
{
type: "node",
c: "#c0c0c0",
id: "07979079238",
t: "07979079238",
},
{
type: "node",
c: "#c0c0c0",
id: "01770637968",
t: "01770637968",
},
{
type: "node",
c: "#c0c0c0",
id: "0126233087",
t: "0126233087",
},
{
type: "node",
c: "#c0c0c0",
id: "01237303110",
t: "01237303110",
},
{
type: "node",
c: "#c0c0c0",
id: "14338475884741",
t: "14338475884741",
},
{
type: "node",
c: "#c0c0c0",
id: "07873361203",
t: "07873361203",
},
{
type: "node",
c: "#c0c0c0",
id: "07189233361",
t: "07189233361",
},
{
type: "node",
c: "#c0c0c0",
id: "07497354521",
t: "07497354521",
},
{
type: "node",
c: "#c0c0c0",
id: "07541477895",
t: "07541477895",
},
{
type: "node",
c: "#c0c0c0",
id: "07690700998",
t: "07690700998",
},
{
type: "node",
c: "#c0c0c0",
id: "07351039125",
t: "07351039125",
},
{
type: "node",
c: "#c0c0c0",
id: "07529309344",
t: "07529309344",
},
{
type: "node",
c: "#c0c0c0",
id: "07216812571",
t: "07216812571",
},
{
// ...truncated 15530 lines <!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="@ci/theme/kl/css/keylines.css" />
<link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/minimalsdk.css" />
<link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/sdk-layout.css" />
<link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/demo.css" />
<script src="jquery" defer type="text/javascript"></script>
</head>
<body>
<div id="klchart" class="klchart klchart-timebar"></div>
<div id="kltimebar" class="kltimebar"></div>
<script type="module" src="./code.js"></script>
</body>
</html>