The KeyLines time bar is a powerful tool for visualising and interacting with dynamic data.
KeyLines events are flexible and customisable and support mouse, keyboard and touch device inputs. The time bar features built-in control buttons, but you can also create your own custom controls.
In this demo you can explore time bar events available for the time bar integration.
While you interact, the events are added to the top of the Event list as they are fired.
The Event details window shows the object passed to the event handler of the active event.
See also
Demos: Interaction Events
Key functions used:
import KeyLines from "keylines";
import data from "./data.js";
let timebar;
const selections = [
{ id: "07086312446-07691640598", index: 0 },
{ id: "07456622368-07252637450", index: 1 },
];
const events = [
"change",
"click",
"context-menu",
"double-click",
"drag-end",
"drag-start",
"end",
"hover",
"key-down",
"key-up",
"pause",
"play",
"pointer-down",
"pointer-move",
"pointer-up",
"start",
"wheel",
];
const ignoreList = ["pointer-move"];
let eventDetails = {};
let eventCounter = 0;
function positionModifierKeys() {
const tbDivRect = document
.getElementById("kltimebar")
.getBoundingClientRect();
const modifierKeysDiv = document.getElementById("modifier-keys");
modifierKeysDiv.style.top = `${tbDivRect.top}px`;
modifierKeysDiv.style.left = `${tbDivRect.left}px`;
modifierKeysDiv.style.opacity = 1;
}
function initialiseInteractions() {
// Create a map of which events should be listened to
const onEvents = new Map(
events
.filter((name) => ignoreList.indexOf(name) === -1)
.map((event) => [event, true]),
);
// Get all the elements we wish to be able to modify
const eventsDropdown = document.getElementById("eventsDropdown");
const eventsContainer = document.getElementById("eventsContainer");
const eventsList = document.getElementById("eventsList");
const noEventsButton = document.getElementById("noEvents");
const allEventsButton = document.getElementById("allEvents");
const eventNameDisplay = document.getElementById("eventName");
const eventDetailsPre = document.getElementById("eventDetails");
const prevEventButton = document.getElementById("prevEvent");
const nextEventButton = document.getElementById("nextEvent");
const eventLog = document.getElementById("eventLog");
const eventsTable = document.getElementById("events");
const clearButton = document.getElementById("clear");
// Get the bounds of the event log so can ensure the highlighted event is in view
const { top: eventLogTop, bottom: eventLogBottom } =
eventLog.getBoundingClientRect();
function displayEvent(evtId) {
const details = eventDetails[evtId];
const json = JSON.stringify(details.event, undefined, 2);
eventDetailsPre.innerHTML = json;
eventDetailsPre.dataset.id = evtId;
eventNameDisplay.innerHTML = `: '${details.name}'`;
// Disable the previous / next event buttons if no such event exists
prevEventButton.disabled = !eventDetails[evtId - 1];
nextEventButton.disabled = !eventDetails[evtId + 1];
}
function highlightRow(eventRow) {
[...document.getElementsByClassName("selectedEvent")].forEach((el) => {
el.classList.remove("selectedEvent");
});
eventRow.classList.add("selectedEvent");
// Check if row is visible, if not scroll into view
const distToTop = eventRow.getBoundingClientRect().top - eventLogTop;
if (distToTop < 0) {
eventLog.scrollTop += distToTop;
} else {
const distToBottom =
eventRow.getBoundingClientRect().bottom - eventLogBottom;
if (distToBottom > 0) {
eventLog.scrollTop += distToBottom;
}
}
}
function onRowClick(rowClickEvt) {
const row = rowClickEvt.currentTarget;
highlightRow(row);
displayEvent(parseInt(row.dataset.lastId, 10));
}
function displayNextEvent() {
// Get the ID of the next event
const evtId = parseInt(eventDetailsPre.dataset.id, 10) + 1;
// Check if it is grouped in the currently highlighted row
const currEvtRow = document.getElementsByClassName("selectedEvent")[0];
if (parseInt(currEvtRow.dataset.lastId, 10) < evtId) {
highlightRow(currEvtRow.previousSibling);
}
// Display the details of this event
displayEvent(evtId);
}
function displayPrevEvent() {
// Get the ID of the previous event
const evtId = parseInt(eventDetailsPre.dataset.id, 10) - 1;
// Check if it is grouped in the currently highlighted row
const currEvtRow = document.getElementsByClassName("selectedEvent")[0];
if (parseInt(currEvtRow.dataset.firstId, 10) > evtId) {
highlightRow(currEvtRow.nextSibling);
}
// Display the details of this event
displayEvent(evtId);
}
// Add the HTML for the event filter
events.forEach((event) => {
// Create a new element
const eventLabel = document.createElement("label");
eventLabel.innerHTML = `<input type="checkbox" id="${event}" ${
onEvents.has(event) ? 'checked="checked"' : ""
}"> ${event}`;
const eventLabelinput = eventLabel.querySelector("input");
// Add the on change listener
eventLabel.addEventListener("change", () => {
onEvents.set(event, eventLabelinput.checked);
});
// Make the no events button disable this input
noEventsButton.addEventListener("click", () => {
eventLabelinput.checked = false;
onEvents.set(event, false);
});
// Make the all events button enable this input
allEventsButton.addEventListener("click", () => {
eventLabelinput.checked = true;
onEvents.set(event, true);
});
// Add it to the event list
eventsList.append(eventLabel);
});
clearButton.addEventListener("click", () => {
clearButton.classList.add("hide");
eventsTable.innerHTML = "";
eventNameDisplay.innerHTML = "";
eventDetailsPre.innerHTML = "No event selected";
eventDetailsPre.dataset.id = undefined;
prevEventButton.disabled = true;
nextEventButton.disabled = true;
eventDetails = {};
});
eventsDropdown.addEventListener("click", (event) => {
const classList = eventsContainer.classList;
if (classList.contains("hide")) classList.remove("hide");
else classList.add("hide");
event.stopPropagation();
});
document.addEventListener("click", (event) => {
if (event.target.closest("#eventsContainer") === null) {
eventsContainer.classList.add("hide");
}
});
nextEventButton.addEventListener("click", displayNextEvent);
prevEventButton.addEventListener("click", displayPrevEvent);
// Attach an event handler to all the time bar events
timebar.on("all", (evt) => {
// Update the active modifier keys
if (evt.event && evt.event.modifierKeys) {
Object.keys(evt.event.modifierKeys).forEach((key) => {
if (evt.event.modifierKeys[key]) {
document.getElementById(key).classList.add("active");
} else {
document.getElementById(key).classList.remove("active");
}
});
}
if (onEvents.get(evt.name)) {
// Add this event to the log
const eventObject = {};
if (evt.event) {
Object.keys(evt.event).forEach((prop) => {
if (prop !== "defaultPrevented") eventObject[prop] = evt.event[prop];
});
}
const lastEvt = eventDetails[eventCounter++];
eventDetails[eventCounter] = { name: evt.name, event: eventObject };
// Check if a repeat of the previous event
if (
eventObject &&
lastEvt &&
evt.name === lastEvt.name &&
eventObject.id === lastEvt.event.id
) {
// Group it with the previous event and up the counter for that event
const td = document.getElementsByClassName("eventname")[0];
const rowData = td.parentElement.dataset;
const countSpan = td.children[0];
countSpan.innerText = `(${eventCounter - rowData.firstId + 1})`;
rowData.lastId = eventCounter;
} else {
// Add it to the top of the event log
const tr = document.createElement("tr");
tr.innerHTML = `<td id='${eventCounter}' class='eventname'>'${evt.name}'<span></span></td>`;
tr.dataset.firstId = eventCounter;
tr.dataset.lastId = eventCounter;
tr.onclick = onRowClick;
eventsTable.insertBefore(tr, eventsTable.firstChild);
}
// Ensure the top row is highlighed
highlightRow(
document.getElementsByClassName("eventname")[0].parentElement,
);
// Update the displayed event details to show this event
displayEvent(eventCounter);
// Unhide the clear button
clearButton.classList.remove("hide");
}
});
// Hide the modifier keys when open the source tab
[...document.getElementsByClassName("tablinks")].forEach((el) => {
el.addEventListener("click", () => {
document.getElementById("modifier-keys").style.opacity =
el.name === "sourceTab" ? 0 : 1;
});
});
}
async function startKeyLines() {
const options = {
showExtend: true,
};
timebar = await KeyLines.create({
container: "kltimebar",
type: "timebar",
options,
});
await timebar.load(data);
timebar.selection(selections);
timebar.zoom("fit", { animate: false });
// Position the modifier keys overlay on the time bar
positionModifierKeys();
window.addEventListener("resize", positionModifierKeys);
// Deactivate them when the time bar isn't focussed
document.getElementById("kltimebar").addEventListener("focusout", () => {
[...document.getElementsByClassName("key")].forEach((el) =>
el.classList.remove("active"),
);
});
initialiseInteractions();
}
window.addEventListener("DOMContentLoaded", startKeyLines); 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 15532 lines <!doctype html>
<html lang="en" style="background-color: #2d383f">
<head>
<meta charset="utf-8" />
<title>Time Bar Events</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" />
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div id="klchart" class="klchart klchart-timebar"></div>
<div id="kltimebar" class="kltimebar"></div>
<div id="modifier-keys" style="position: absolute; pointer-events: none">
<span class="key" id="alt">alt</span><span class="key" id="ctrl">ctrl</span
><span class="key" id="consistentCtrl">consistentCtrl</span
><span class="key" id="meta">meta</span><span class="key" id="shift">shift</span>
</div>
<script type="module" src="./code.js"></script>
</body>
</html> #events .eventname {
color: #00aa70;
font-family:
Monaco,
Andale Mono,
Courier New,
monospace;
padding: 4px 5px;
font-size: 14px;
cursor: pointer;
}
#eventsDropdown {
border-color: #cacdcf;
border-style: solid;
border-width: 1px;
border-radius: 3px;
padding: 6px;
cursor: pointer;
background-color: #fff;
margin-top: 10px;
}
#eventsDropdown .icon-chevron-down {
width: 12px;
height: 12px;
border-color: #333;
border-style: solid;
border-width: 4px 4px 0px 0px;
transform: rotate(135deg);
margin-right: 5px;
}
#eventsContainer {
width: 368px;
border-width: 1px;
border-color: #cacdcf;
border-top: 0px;
border-style: solid;
border-radius: 3px;
padding-bottom: 8px;
background-color: #ffffff;
position: absolute;
margin-left: 0px;
z-index: 1000;
scrollbar-width: none;
}
#eventsList {
padding: 6px;
width: 100%;
}
#eventsList label {
display: inline-block;
margin: 4px 50px 4px 0px;
width: calc(49% - 50px);
cursor: pointer;
}
#noEvents {
margin-left: 6px;
}
#eventLog {
height: 250px;
overflow-y: auto;
margin-bottom: 10px;
clear: both;
border: 1px solid #ccc;
background-color: #fff;
cursor: ns-resize;
}
#eventLog table {
margin-bottom: 5px;
}
#events .selectedEvent {
background-color: #ddd;
}
#eventDetails {
height: 250px;
width: 100%;
overflow-y: auto;
}
#modifier-keys {
opacity: 0;
}
.key {
background-color: #b2df8a;
border: 2px solid #ffffff;
display: inline-block;
color: #5e5e5e;
font: 14px arial;
text-decoration: none;
text-align: center;
margin: 3px 3px;
padding: 6px 6px;
}
.key.active {
border-color: #ffaf00;
background-color: #ffaf00;
}
/* make the time bar fill the area vertically */
.kltimebar {
height: 100%;
}
@media (max-width: 979px) {
#eventsContainer {
width: 326px;
}
#eventsList label {
margin-right: 11px;
width: calc(49% - 11px);
}
}
@media (max-width: 767px) {
#eventsContainer {
width: 266px;
}
#eventsList label {
margin-right: 30px;
width: calc(49% - 30px);
}
}