//
// Copyright © 2011-2025 Cambridge Intelligence Limited.
// All rights reserved.
//
// Sample Code
//! Set the look and feel of the time bar.
import KeyLines from "keylines";
import { data } from "./basic-data.js";
let timebar;
let defaultOptions;
let minScaleIndex;
let maxRangeIndex;
const time1 = new Date("26 Jul 2010");
const time2 = new Date("31 Jul 2010");
const colours = {
blue: "#0B93B2",
green: "#0A8254",
red: "#e03038",
lightblue: "#6cbed0",
lightgreen: "#53a787",
};
const locales = {
de: {
longMonths: [
"Januar",
"Februar",
"März",
"April",
"Mai",
"Juni",
"Juli",
"August",
"September",
"Oktober",
"November",
"Dezember",
],
shortMonths: [
"Jan",
"Feb",
"Mär",
"Apr",
"Mai",
"Jun",
"Jul",
"Aug",
"Sep",
"Okt",
"Nov",
"Dez",
],
ampm: ["AM", "PM"],
quarter: "Q",
half: "H",
},
en: {
longMonths: [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
],
shortMonths: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
],
ampm: ["AM", "PM"],
quarter: "Q",
half: "H",
},
es: {
longMonths: [
"enero",
"febrero",
"marzo",
"abril",
"mayo",
"junio",
"julio",
"agosto",
"septiembre",
"octubre",
"noviembre",
"diciembre",
],
shortMonths: [
"ene",
"feb",
"mar",
"abr",
"may",
"jun",
"jul",
"ago",
"sep",
"oct",
"nov",
"dic",
],
ampm: ["a.m.", "p.m."],
quarter: "T", // trimestre
half: "S", // semestre
},
fr: {
longMonths: [
"janvier",
"février",
"mars",
"avril",
"mai",
"juin",
"juillet",
"août",
"septembre",
"octobre",
"novembre",
"décembre",
],
shortMonths: [
"jan",
"fév",
"mars",
"avr",
"mai",
"juin",
"juil",
"août",
"sep",
"oct",
"nov",
"déc",
],
ampm: ["AM", "PM", "matin", "soir"], // Demonstrates AM/PM interval labelling
quarter: "T", // trimestre
half: "S", // semestre
},
it: {
longMonths: [
"gennaio",
"febbraio",
"marzo",
"aprile",
"maggio",
"giugno",
"luglio",
"agosto",
"settembre",
"ottobre",
"novembre",
"dicembre",
],
shortMonths: [
"gen",
"feb",
"mar",
"apr",
"mag",
"giu",
"lug",
"ago",
"set",
"ott",
"nov",
"dic",
],
ampm: ["AM", "PM"],
quarter: "T", // trimestre
half: "S", // semestre
},
};
function getSliderColour(backColour) {
if (backColour === "black") {
return "rgba(0, 0, 0, 0.7)";
}
if (backColour === "grey") {
return "rgba(0, 0, 0, 0.3)";
}
return defaultOptions.sliderColour;
}
// Turn minScale string into setting
function makeMinScale(s) {
if (s) {
const parts = s.split(",");
return { units: parts[0], value: parseInt(parts[1], 10) };
}
// reset to default
return { units: "sec", value: 1 };
}
// Turn maxRange string into setting
function makeMaxRange(s) {
if (s) {
const parts = s.split(",");
return { units: parts[0], value: parseInt(parts[1], 10) };
}
// otherwise reset to default
return "auto";
}
function isMinScaleBiggerThanMaxRange() {
return minScaleIndex >= maxRangeIndex;
}
function handleRangeErrorMessage() {
$("#range-scale").toggle(isMinScaleBiggerThanMaxRange());
}
function resetZoom() {
timebar.zoom("fit", { animate: false });
}
// Set options according to the controls on the Options tab
async function setOptions() {
const backColour = $("select[name=background]").val();
const newSliderMode = $("select[name=sliders]").val();
let fontSize = $("input[name=fontsize]").val();
handleRangeErrorMessage();
if (fontSize <= 50) {
if (fontSize >= 5) fontSize = $("input[name=fontsize]").val();
else fontSize = 5;
} else fontSize = 50;
const options = {
area: {
colour:
colours[$("select[name=areacolour]").val()] ||
defaultOptions.area.colour,
},
minScale: makeMinScale($("select[name=minscale]").val()),
maxRange: makeMaxRange($("select[name=maxrange]").val()),
showPlay: $("input[name=play]").is(":checked"),
showExtend: $("input[name=playextend]").is(":checked"),
showFit: $("input[name=fit]").is(":checked"),
showControlBar: $("input[name=controlbar]").is(":checked"),
scale: {
showMinor: $("input[name=minor]").is(":checked"),
showMajor: $("input[name=major]").is(":checked"),
},
sliders: newSliderMode,
playSpeed: $("#playSlider").slider("value"),
backColour,
sliderColour: getSliderColour(backColour),
fontColour: backColour === "grey" ? "white" : defaultOptions.fontColour,
fontFamily: $("select[name=fontfamily]").val(),
fontSize,
histogram: {
colour:
colours[$("select[name=colour]").val()] ||
defaultOptions.histogram.colour,
highlightColour:
colours[$("select[name=highlightcolour]").val()] ||
defaultOptions.histogram.highlightColour,
markColour:
colours[$("select[name=markcolour]").val()] ||
defaultOptions.histogram.markColour,
markHiColour:
colours[$("select[name=markhicolour]").val()] ||
defaultOptions.histogram.markHiColour,
},
heightChange: {
animate: $("input[name=heightchange]").is(":checked"),
time: $("#hcSlider").slider("value"),
},
groups: {
groupBy: $("select[name=group]").val() === "none" ? null : "type",
categories:
$("select[name=group]").val() === "one"
? ["Low"]
: ["Low", "Medium", "High"],
},
type: $("select[name=type]").val(),
};
// we need this for later
const oldSliderMode = timebar.options().sliders;
await timebar.options(options);
// if we change mode call zoom fit
if (oldSliderMode !== newSliderMode) {
resetZoom();
}
}
// Set localisation options
function setLocale() {
const options = {
locale: $.extend(locales[$(".locale.active").val()], {
order: $("input[name=order]:checked").val(),
h12: $("input[name=hours]:checked").val() === "h12",
}),
};
timebar.options(options);
}
function setupFormControls() {
$("#rhsForm").on("submit", (e) => e.preventDefault()); // prevent the form to submit
$("#style").on("change click", ":input", setOptions);
$("#options").on("change", ":input", setOptions);
$("#type").on("change", () => {
// Switch between the correct colour options for type (histogram/area)
$("#options-histogram").toggle(500);
$("#options-area").toggle(500);
});
// Start with area colour section hidden
$("#options-area").toggle();
$("#localisation").on("change", ":input", setLocale);
$(".maxrange").on("change", (e) => {
maxRangeIndex = $(e.currentTarget).find("option:selected").attr("index");
});
$(".minscale").on("change", (e) => {
minScaleIndex = $(e.currentTarget).find("option:selected").attr("index");
});
// range slider to set speed
$("#playSlider").slider({
min: 10,
max: 150,
value: defaultOptions.playSpeed,
change() {
const speed = $(this).slider("value");
$("#playSpeed").text(speed);
// when slider changes update the playSpeed to current value
timebar.options({ playSpeed: speed });
},
});
// show initial play speed
$("#playSpeed").text(defaultOptions.playSpeed);
$("#hcSlider").slider({
min: 10,
max: 500,
step: 10,
value: defaultOptions.heightChange.time,
change() {
const time = $(this).slider("value");
$("#hcTime").text(time);
timebar.options({ heightChange: { time } });
},
});
$("#hcTime").text(defaultOptions.heightChange.time);
// locale buttons
$(".locale").on("click", (e) => {
$(".locale").removeClass("active btn-kl");
$(e.currentTarget).addClass("active btn-kl");
setLocale();
});
// changing to localisation tab should zoom in to properly demonstrate how options affect times
// and dates
let cachedOptions = null;
let cachedRange = null;
$("#rhscontent .nav a").on("click", async (e) => {
if ($(e.currentTarget).text() === "Localisation") {
// cache options
cachedOptions = timebar.options();
cachedRange = timebar.range();
// zoom in and ensure options make sense to properly display dates
await timebar.options({
sliders: "fixed",
scale: {
showMinor: true,
showMajor: true,
},
});
await timebar.range(new Date(2010, 6, 27), new Date(2010, 6, 28));
// Reset the localisation buttons
$(".locale.active").removeClass("btn-kl active");
$("input[value=en]").addClass("btn-kl active");
$("input[value=h12]").prop("checked", true);
$("input[value=mdy]").prop("checked", true);
} else if (cachedOptions) {
// restore cached options
await timebar.options(cachedOptions);
cachedOptions = null;
timebar.range(cachedRange.dt1, cachedRange.dt2);
}
});
}
function loaded() {
timebar.mark({ dt1: time1, dt2: time2 });
resetZoom();
}
async function klReady(bar) {
// save the timebar reference
timebar = bar;
// now load the data in the timebar: that's it!
await timebar.load(data);
loaded();
// get default options so we can return to factory settings after we have changed options
defaultOptions = timebar.options();
setupFormControls();
// setOptions so that time bar matches current state of the form
await setOptions();
}
$(function () {
KeyLines.create({ container: "kltimebar", type: "timebar" }).then(klReady);
});
<!DOCTYPE html>
<html lang="en" style="background-color: #2d383f;">
<head>
<meta charset="UTF-8">
<title>Customise the Time Bar</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">
<link rel="stylesheet" type="text/css" href="/css/jquery-ui.css">
<link rel="stylesheet" type="text/css" href="/basic.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="/vendor/bootstrap.js" defer type="text/javascript"></script>
<script src="/vendor/jquery-ui.js" defer type="text/javascript"></script>
<script src="/basic-data.js" defer type="module"></script>
<script src="/basic.js" defer 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="kltimebar">
</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%;">Customise the Time Bar</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">
<ul class="nav nav-tabs">
<li class="tab-links active"><a href="#style" data-toggle="tab">Appearance</a></li>
<li class="tab-links"><a href="#options" data-toggle="tab">Options</a></li>
<li class="tab-links"><a href="#localisation" data-toggle="tab">Localisation</a></li>
</ul>
<div id="optionsForm">
<div class="tab-content" style="overflow: inherit;">
<div class="tab-pane active" id="style">
<label>Time bar type</label>
<select name="type" id="type">
<option value="histogram">Histogram bars</option>
<option value="area">Smooth area</option>
</select>
<div id="options-histogram">
<label>Data grouping</label>
<select name="group">
<option value="none" selected="selected">None (default)</option>
<option value="all">All in groups</option>
<option value="one">One group</option>
</select>
<label>Background colour</label>
<select name="background">
<option value="white" selected="selected">white (default)</option>
<option value="grey">grey</option>
<option value="black">black</option>
</select>
<label>Histogram colour</label>
<select name="colour">
<option value="default" selected="selected">light grey (default)</option>
<option value="blue">blue</option>
<option value="green">green</option>
<option value="red">red</option>
</select>
<label>Histogram highlight colour</label>
<select name="highlightcolour">
<option value="default" selected="selected">grey (default)</option>
<option value="blue">blue</option>
<option value="green">green</option>
<option value="red">red</option>
</select>
<label>Histogram mark colour</label>
<select name="markcolour">
<option value="lightblue">light blue</option>
<option value="lightgreen">light green</option>
<option value="default" selected="selected">light red (default)</option>
</select>
<label>Histogram mark highlight colour</label>
<select name="markhicolour">
<option value="blue">blue</option>
<option value="green">green</option>
<option value="default" selected="selected">red (default)</option>
</select>
</div>
<div id="options-area">
<label>Area colour</label>
<select name="areacolour">
<option value="green">green</option>
<option value="red">red</option>
<option value="default" selected="selected">blue (default)</option>
</select>
</div>
<label>Font family & size</label>
<div class="form-inline">
<select class="inline" name="fontfamily">
<option value="sans-serif">Sans Serif</option>
<option value="wide">Wide</option>
<option value="tahoma">Tahoma</option>
<option value="georgia">Georgia</option>
</select>
<input class="input-small inline" type="number" name="fontsize" value="12" min="5" max="50">
</div>
<div style="margin-top: 10px;">
<label class="checkbox inline">
<input type="checkbox" name="controlbar" checked>Control Bar
</label>
<label class="checkbox inline">
<input type="checkbox" name="minor" checked>Minor Scale
</label>
<label class="checkbox inline">
<input type="checkbox" name="major" checked>Major Scale
</label>
</div>
</div>
<div class="tab-pane" id="options">
<label class="checkbox">
<input type="checkbox" name="play" checked>Show Play Button
</label>
<label class="checkbox">
<input type="checkbox" name="playextend">Show Extend Button
</label>
<label class="checkbox">
<input type="checkbox" name="fit" checked>Show Fit Button
</label>
<label>Minimum scale</label>
<select class="minscale" name="minscale">
<option value="" selected="selected" index="0">None</option>
<option value="month,1" index="7">One month</option>
<option value="week,1" index="6">One week</option>
<option value="day,1" index="5">One day</option>
<option value="hour,12" index="4">12 hours</option>
<option value="hour,6" index="3">6 hours</option>
<option value="hour,1" index="2">One hour</option>
<option value="min,1" index="1">One minute</option>
</select>
<label style="color:red" id="range-scale">Maximum range cannot be smaller than or equal to Minimum scale.</label>
<label>Maximum range</label>
<select class="maxrange" name="maxrange">
<option value="" selected="selected" index="10">None</option>
<option value="year,10" index="9">Ten years</option>
<option value="year,1" index="8">One year</option>
<option value="month,1" index="7">One month</option>
<option value="week,1" index="6">One week</option>
<option value="day,1" index="5">One day</option>
<option value="hour,12" index="4">12 hours</option>
<option value="hour,6" index="3">6 hours</option>
</select>
<label>Sliders</label>
<select name="sliders">
<option value="fixed">Fixed</option>
<option value="free">Free</option>
<option value="none">None</option>
</select>
<label class="pad">Play speed: <span class="stat" id="playSpeed"></span>
<div class="slider" id="playSlider"></div>
</label>
<label class="pad checkbox">
<input type="checkbox" name="heightchange" checked>Animate histogram height
</label>
<label>Time: <span class="stat" id="hcTime"></span>
<div class="slider" id="hcSlider"></div>
</label>
</div>
<div class="tab-pane" id="localisation">
<div style="margin-left:5px">
<p>Language: </p>
<div class="btn-group">
<input class="locale size btn" type="button" value="de">
<input class="locale size btn btn-kl active" type="button" value="en">
<input class="locale size btn" type="button" value="es">
<input class="locale size btn" type="button" value="fr">
<input class="locale size btn" type="button" value="it">
</div>
<fieldset>
<p style="margin-top:10px">Hours:</p>
<label class="radio">
<input type="radio" name="hours" value="h12" checked="checked">12-hour clock
</label>
<label class="radio">
<input type="radio" name="hours" value="h24">24-hour clock
</label>
</fieldset>
<fieldset>
<p style="margin-top:10px">Date order:</p>
<label class="radio">
<input type="radio" name="order" value="dmy">Day, month, year
</label>
<label class="radio">
<input type="radio" name="order" value="mdy" checked="checked">Month, day, year
</label>
</fieldset>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div id="moreParent">
<div id="moreContainer">
</div>
</div>
<div id="lazyScripts">
</div>
</body>
</html>
.slider {
margin: 10px;
}
.stat {
border: 1px solid #cacdcf;
padding: 4px;
background: #F5F5F5;
}
#playSlider, #hcSlider {
display: inline-block;
width: 180px;
}
.pad {
margin-bottom: 10px;
}
.kltimebar {
height: 100%;
}
.input-small {
min-height: 38px;
width: 46px;
}
.nav-tabs {
border-bottom: 1px solid #ccc;
padding: 0px;
}
.tab-links {
display: inline-block;
}
.tab-links:not(:first-child) {
margin-left: -4px
}
.tab-links.active {
border: 0px 0px 3px 0px solid #00aa70;
}
.tab-pane.active {
display: block;
visibility: visible;
overflow: hidden;
}
input.inline {
margin-left: 10px;
}
Loading source
