Search

Animate Filtering by Time

Time

Select, compare and display time-based activities.

Animate Filtering by Time
View live example →

This demo illustrates the powerful analysis possible when the data evolves over time. KeyLines can be used to investigate the 'when' as well as the 'what'.

By displaying the graph simultaneously with the time bar a variety of interactions are possible. With the full dataset shown, selecting nodes on the graph will automatically highlight their activity on the time bar, providing insight as to the distribution of activity (phone calls in this case) over the whole time period.

Use of animation

Additional insight can be gained by playing an animation of the chart. If the time bar sliders are narrowed to approximately 1 month (September) and the play button pressed then the dynamic evolution of the data (representing a social network) can be seen.

Operation and appearance

When 'paused', the time bar can be dragged backwards and forwards to find the exact moment of an event. Note the use of KeyLines's ping function to draw attention to nodes entering the chart's selected timeframe.

Data

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 { chartData, baseColor, selectionColours } from "./data.js";

let chart;
let timebar;

const hideElement = document.getElementById("hide");
const selectionOnlyElement = document.getElementById("selonly");
const tooltipElement = document.getElementById("tooltip");
const chartElement = document.getElementById("klchart");
const arrow = document.querySelector(".tooltip-arrow");
const inner = document.querySelector(".tooltip-inner");

// Find the neighbours of the selection to two levels deep
function computeNeighboursOfSelection() {
  let items = chart.selection();

  if (items.length > 0) {
    const neighbours = chart.graph().neighbours(items, { hops: 2 });
    items = items.concat(neighbours.nodes, neighbours.links);
    return new Set(items);
  }
  return new Set();
}

function showSelection() {
  const visualProperties = {};

  chart.each({ type: "all" }, (item) => {
    visualProperties[item.id] = { id: item.id, c: baseColor, ha1: false };
  });

  let selectedIds = chart.selection();

  // we only colour the first few items of the selection
  selectedIds = selectedIds.slice(0, selectionColours.length);

  // clear all selections
  timebar.selection([]);

  const items = [];

  selectedIds.forEach((id, index) => {
    const fromNodes = [];
    let links = [];
    let toNodes = [];

    const item = chart.getItem(id);

    if (item.type === "node") {
      fromNodes.push(id);

      // note we use all: true so that we apply styles also to
      // hidden nodes and links that aren't in the current time range
      const toNeighbours = chart
        .graph()
        .neighbours(id, { direction: "from", all: true });
      links = toNeighbours.links;
      toNodes = toNeighbours.nodes;
    } else {
      // it is a link
      links.push(id);

      // use the arrows to decide which list to put the nodes on
      (item.a1 ? toNodes : fromNodes).push(item.id1);
      (item.a2 ? toNodes : fromNodes).push(item.id2);
    }

    fromNodes.concat(links).forEach((itemId) => {
      visualProperties[itemId].c = selectionColours[index];
    });

    toNodes.forEach((nodeId) => {
      visualProperties[nodeId].ha1 = {
        w: 5,
        r: 27,
        c: selectionColours[index],
      };
    });

    // and select in the timebar
    // be careful to include the id of the thing selected too - this is necessary when selecting
    // links only
    items.push({ id: links, index, c: selectionColours[index] });
  });

  timebar.selection(items);

  chart.setProperties(Object.values(visualProperties));
}

async function afterFiltering(nodesShown, nodesHidden, selBefore) {
  const connectedItems = selectionOnlyElement.checked
    ? computeNeighboursOfSelection()
    : new Set();

  let pingNodes = nodesShown;
  if (connectedItems.size) {
    const result = await chart.filter((item) => connectedItems.has(item.id), {
      animate: false,
    });
    pingNodes = pingNodes.concat(result.shown.nodes);
  }

  // if the nodes displayed have changed then run an adaptive layout
  if (pingNodes.length > 0 || nodesHidden.length > 0) {
    chart.layout("organic", { animate: true, time: 500, mode: "adaptive" });
  }

  if (pingNodes.length > 0) {
    chart.ping(pingNodes, { time: 1500, c: "rgb(178, 38, 9)" });
  }

  // If our filtering has hidden any selected items, then we need to update
  // the selection lines in the timebar
  if (selBefore.length !== chart.selection().length) {
    showSelection();
  }
}

async function timebarChanged() {
  if (hideElement.checked) {
    const selBefore = chart.selection();
    const result = await chart.filter(timebar.inRange, {
      animate: false,
      type: "link",
    });
    afterFiltering(result.shown.nodes, result.hidden.nodes, selBefore);
  } else {
    chart.foreground(timebar.inRange, { type: "link" });
  }
}

// When the user changes the hide checkbox, swap items from
// being hidden to background items
function hideToggled() {
  const hi = hideElement.checked;

  const items = [];
  chart.each({ type: "all" }, (item) => {
    if (item[hi ? "bg" : "hi"]) {
      items.push({ id: item.id, bg: !hi, hi });
    }
  });
  chart.setProperties(items);
}

function showTooltip({ type, index, value, tooltipX, tooltipY }) {
  // the offset is taken from the top-left corner of the chart
  // calculate the height of the chart to start from the top-left of the timebar
  const offset = { top: document.getElementById("kl").height, left: 0 };

  const toShow = type === "bar" || type === "selection";

  if (toShow) {
    // change the content
    document.getElementById("tooltipText").innerText = `Value: ${value}`;

    // selection colour or default colour for bar hover
    const tooltipColour = selectionColours[index] || "";

    // style both the tooltip body and the arrow
    arrow.style.backgroundColor = tooltipColour;
    inner.style.backgroundColor = tooltipColour;

    // in case of default colour or red (selection 2)
    const isBetterWhite = tooltipColour.length === 0 || index > 1;

    // white works better in same cases
    inner.style.color = isBetterWhite ? "white" : "black";

    // the top needs to be adjusted to accommodate the height of the tooltip,
    // the chart height and an aesthetic offset
    offset.top =
      tooltipY - (tooltipElement.clientHeight + 8) + chartElement.clientHeight;

    // shift left by half width to centre it
    offset.left = tooltipX - tooltipElement.clientWidth / 2 + 8;
  }

  // set the position and toggle the "in" class to show/hide the tooltip
  tooltipElement.style.left = `${offset.left}px`;
  tooltipElement.style.top = `${offset.top}px`;
  if (toShow) {
    tooltipElement.classList.remove("hidden");
  } else {
    tooltipElement.classList.add("hidden");
  }
}

function initaliseEvents() {
  // Chart events to react to
  chart.on("selection-change", timebarChanged);
  chart.on("selection-change", showSelection);

  // Time bar events to react to
  timebar.on("change", () => {
    tooltipElement.classList.add("hidden");
    timebarChanged();
  });
  timebar.on("hover", showTooltip);

  hideElement.addEventListener("click", () => {
    hideToggled();
    const checked = hideElement.checked;
    selectionOnlyElement.disabled = !checked;
    if (selectionOnlyElement.disabled) {
      selectionOnlyElement.checked = false;
    }
    document.getElementById("solab").style.color = checked ? "" : "silver";
  });
  selectionOnlyElement.addEventListener("click", timebarChanged);
}

async function startKeyLines() {
  const chartOptions = {
    handMode: true,
    logo: { u: "/public/images/Logo.png" },
    overview: { icon: false, shown: false },
  };

  const timeBarOptions = {
    playSpeed: 30,
  };

  [chart, timebar] = await KeyLines.create([
    { id: "kl", container: "klchart", type: "chart", options: chartOptions },
    { container: "kltimebar", type: "timebar", options: timeBarOptions },
  ]);

  initaliseEvents();

  // load the data into timebar and chart
  timebar.load(chartData);
  chart.load(chartData);
  timebar.zoom("fit", { animate: false });
  chart.layout("organic", { packing: "circle" });
}

window.addEventListener("DOMContentLoaded", startKeyLines);
export const chartData = {
  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 16601 lines
<!doctype html>
<html lang="en" style="background-color: #2d383f">
  <head>
    <meta charset="utf-8" />
    <title>Animate Filtering by Time</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" />
    <style type="text/css">
      .tooltip {
        display: block;
        opacity: 0.5;
        position: absolute;
        pointer-events: none;
        z-index: 1;
      }
      .tooltip-inner {
        line-height: 30px;
        margin: 0px;
      }
      .tooltip-inner p {
        margin: 0px;
      }
      .tooltip.top .tooltip-arrow {
        display: unset;
        width: 20px;
        height: 20px;
        background-color: #2d3741;
        transform: rotateZ(45deg);
        position: absolute;
        top: 29px;
        left: 29px;
      }
    </style>
  </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>

Terms of use

These terms do not alter or supersede any existing agreements between you (or your employer) and us.

By accessing or using any Content you agree to be bound by these Terms of Use. Please review these terms carefully before using the website.

The contents of this website, including but not limited to any text, code samples, API references, schemas, interactive tools, and other materials (collectively, the 'Content'), are made available for informational and internal evaluation purposes only. All intellectual property rights in the Content are reserved. No licence is granted to use the Content for any commercial purpose, or to copy, distribute, modify, reverse-engineer, or incorporate any part of the Content into any product or service, without our prior written consent.

This Content is provided “as is” and “as available,” without any representations, warranties, or guarantees of any kind, whether express or implied, including but not limited to implied warranties of merchantability, fitness for a particular purpose, non-infringement, or accuracy. To the fullest extent permitted by applicable law, we expressly exclude and disclaim all implied warranties, conditions, and other terms that might otherwise be implied.

We disclaim all liability for any loss or damage, whether direct, indirect, incidental, consequential, or otherwise, arising from any reliance placed on the Content or from your use of it, to the fullest extent permitted by applicable law. By continuing to access or use the Content, you acknowledge and agree to these terms.