//
//     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 &amp; 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: &nbsp;<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: &nbsp;<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:&nbsp;</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