Search

Heatmap Colors

Heatmap

Reveal hidden data patterns with custom color schemes.

Heatmap Colors
View live example →

Use the control below the timeline to select a heatmap color scheme.

Customizing the colors used for the heatmap can provide an alternative view of your events data.

By default, each heatmap cell will take the average color of all events in the cells it contains. Alternatively, you can set your own color schemes or even color cells based on the events they contain.

See also:

import { createTimeline } from "kronograph";
import data from "./data";

const timeline = createTimeline("my-timeline");

const timelineOptions = {
  events: {
    heatmapThreshold: 20,
    heatmapValue: "amount",
    heatmapColor: "orange",
  },
};

const colorOptions = {
  // Cells will be colored orange with an alpha value based on the value distribution.
  orange: "orange",
  // Cells will be colored from the given color array based on a percentile distribution of all cell values.
  sequential: ["#dbe2af", "#f3bf5e", "#e89b53", "#cf7047", "#a93e3c", "#7a002d"],
  steps: [
    { value: -1, color: "#fa8072" }, // First value is always ignored, cells default to #fa8072 (red).
    { value: 0, color: "#00a2ed" }, // Cells with values above the threshold of zero will be #00a2ed (blue).
  ],
  type: [
    { eventType: "alert", color: "red" }, // If a cell includes an event with type 'alert', it will be red.
    { eventType: "warning", color: "yellow" }, // If a cell includes an event with type 'warning', it will be yellow.
    { eventType: "default", color: "gray" }, // All other cells will be a gray color.
  ],
};

document.getElementById("heatmap-color-select").addEventListener("change", changeHandler);
timeline.options(timelineOptions);
timeline.set(data);
timeline.fit();

timeline.on("draw", () => {
  // Update the position of the legend in relation to the bottom entity when the timeline is drawn.
  const visibleLegend = document.querySelector(".story__legend:not(.hidden)");
  const maxY = Object.keys(timeline.getInRangeItems().entities).reduce(
    (max, entityName) => Math.max(max, timeline.getEntityPosition(entityName)?.y2 ?? 0),
    0
  );
  if (visibleLegend) {
    visibleLegend.style.top = `${maxY + 20}px`; // Position the legend below the lowest entity.
  }
});

const legends = {
  orange: makeOrangeAlphaLegend(),
  sequential: makeSequentialLegend(),
  steps: makeStepsLegend(),
  type: makeTypeLegend(),
};

function makeOrangeAlphaLegend() {
  const legendEntries = [];
  // create legend entries with different alpha values of orange and label them.
  for (let i = 1; i < 4; i++) {
    const alphaMultiplier = 1 / i;
    const legendColor = `rgb(255,165,0,${alphaMultiplier})`;
    const legendText = i === 1 ? "Highest amount" : i === 3 ? "Lowest amount" : "";
    legendEntries[i - 1] = { legendColor, legendText };
  }
  return drawLegend("orange", legendEntries);
}

function makeSequentialLegend() {
  // create legend entries for each of the sequential options and label them.
  const legendEntries = colorOptions.sequential.map((legendColor, i) => {
    return { legendColor, legendText: `range ${i + 1}` };
  });
  return drawLegend("sequential", legendEntries);
}

function makeStepsLegend() {
  const legendEntries = [];
  // create legend Entries for each of the color steps and label them.
  const colors = Object.keys(colorOptions.steps).map((step) => colorOptions.steps[step].color);
  colors.forEach((legendColor, i) => {
    const legendText = i === 0 ? "Values up to 0" : i === 1 ? "Values above 0" : "";
    legendEntries[i] = {
      legendColor,
      legendText,
    };
  });
  return drawLegend("steps", legendEntries);
}

function makeTypeLegend() {
  const legendEntries = [];
  // create legend entries for each type and label them.
  const types = colorOptions.type;
  Object.keys(types).forEach((t, i) => {
    const type = types[t];
    legendEntries[i] = {
      legendColor: type.color,
      legendText: type.eventType,
    };
  });
  return drawLegend("type", legendEntries);
}

function drawLegend(legendId, legendEntries) {
  // draw the legend
  const legendsContainer = document.getElementById("legends");
  const legendElement = document.createElement("div");
  legendElement.classList.add("story__legend");
  if (legendId !== "orange") {
    legendElement.classList.add("hidden");
  }

  legendElement.id = legendId;
  legendEntries.forEach((item) => {
    // Create the row.
    const legendRow = document.createElement("div");
    legendRow.classList.add("story__legend__row");
    // Create the colored legend square.
    const square = document.createElement("div");
    square.classList.add("story__legend__item");
    square.style.backgroundColor = item.legendColor;
    // Create the label for the legend square.
    const text = document.createElement("div");
    text.classList.add("story__legend__text");
    text.innerHTML = item.legendText;
    // Add the square and the text to the row.
    legendRow.append(square, text);
    // Add the row to the legend.
    legendElement.append(legendRow);
  });
  legendsContainer.append(legendElement);
  return legendElement;
}

// change the displayed heatmap type and show the appropriate legend
function changeHandler(e) {
  const { value } = e.target;
  const heatmapColor = colorOptions[value] || null; // Assign the selected color option to heatmapColor.
  Object.keys(legends).forEach((i) => {
    legends[i].classList.add("hidden"); // Hide all the legends.
  });
  if (heatmapColor) {
    legends[value].classList.remove("hidden"); // Show the legend for the specified color option.
  }
  timeline.options({ events: { heatmapColor } });
}
export default {
  entities: {
    "Aurora Bancorp": {
      color: "#4e79a7",
    },
    "Better Life Bank": {
      color: "#f28e2c",
    },
    "Ace Financial Group": {
      color: "#e15759",
    },
    "Grand Mutual Bank": {
      color: "#76b7b2",
    },
    "Felicity Financial Services": {
      color: "#59a14f",
    },
  },
  events: {
    event0: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: -103,
      },
      time: 1716845042401.983,
      type: "warning",
    },
    event1: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 1522,
      },
      time: 1704300247970.444,
    },
    event2: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 2519,
      },
      time: 1704826361998.4548,
    },
    event3: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 1744,
      },
      time: 1721561387584.9785,
    },
    event4: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 1292,
      },
      time: 1721436187577.0662,
    },
    event5: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 1913,
      },
      time: 1715184891178.0125,
    },
    event6: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 1379,
      },
      time: 1720022197785.7358,
    },
    event7: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 2108,
      },
      time: 1713047293850.0168,
    },
    event8: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 39987,
      },
      time: 1719556922296.1238,
    },
    event9: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 6269,
      },
      time: 1717726178569.1255,
    },
    event10: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 4629,
      },
      time: 1718167137411.861,
    },
    event11: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 4112,
      },
      time: 1719690540773.6128,
    },
    event12: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 44477,
      },
      time: 1718653783292.392,
    },
    event13: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 86674,
      },
      time: 1719055763972.7158,
    },
    event14: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 96953,
      },
      time: 1718812764374.0154,
    },
    event15: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 57831,
      },
      type: "alert",
      time: 1717355969771.8218,
    },
    event16: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: 1992,
      },
      time: 1721029217990.7224,
    },
    event17: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: 471,
      },
      time: 1722545977814.828,
    },
    event18: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: 2274,
      },
      time: 1712785338304.0298,
    },
    event19: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: 3067,
      },
      time: 1706715885813.1304,
    },
    event20: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: -670,
      },
      time: 1705034721408.0198,
    },
    event21: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: -648,
      },
      time: 1719489884462.4038,
    },
    event22: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: 325,
      },
      time: 1721614571235.6663,
    },
    event23: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: 851,
      },
      time: 1705237236251.1895,
    },
    event24: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: 3121,
      },
      time: 1721380170448.32,
    },
    event25: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: -1778,
      },
      time: 1719476838892.334,
    },
    event26: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: 3781,
      },
      time: 1714459016034.4941,
    },
    event27: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: 1165,
      },
      time: 1713136401986.9214,
    },
    event28: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: 2237,
      },
      time: 1712559528845.578,
    },
    event29: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: 1535,
      },
      time: 1720931783679.7734,
    },
    event30: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: -1622,
      },
      time: 1721528143853.7964,
    },
    event31: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: 523,
      },
      time: 1709514478039.349,
    },
    event32: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 1257,
      },
      time: 1715409427247.5706,
    },
    event33: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 736,
      },
      time: 1707482336867.2246,
    },
    event34: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 184,
      },
      time: 1725199319145.929,
    },
    event35: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 1058,
      },
      time: 1713232568113.0273,
    },
    event36: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 1429,
      },
      time: 1721868788309.195,
    },
    event37: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: -5097,
      },
      type: "warning",
      time: 1707839323010.2188,
    },
    event38: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 2522,
      },
      time: 1717712034817.7363,
    },
    event39: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 3094,
      },
      time: 1724919209625.5513,
    },
    event40: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 1121,
      },
      time: 1718493292818.4546,
    },
    event41: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 2878,
      },
      time: 1714709244615.406,
    },
    event42: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 1504,
      },
      time: 1715372672224.4255,
    },
    event43: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 320,
      },
      time: 1710331215554.826,
    },
    event44: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 1906,
      },
      time: 1710184345462.6362,
    },
    event45: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: -1246,
      },
      time: 1725198486655.9883,
    },
    event46: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: -1476,
      },
      time: 1706451804586.463,
    },
    event47: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: -192,
      },
      time: 1723811742494.3857,
    },
  },
  eventTypes: {
    alert: {
      color: "red",
    },
    warning: {
      color: "yellow",
    },
    default: {
      color: "grey",
    },
  },
};
<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="@ci/theme/kg/css/examples.css" />
    <link rel="stylesheet" href="./style.css" />
  </head>
  <body>
    <div class="story">
      <div class="story__timeline" id="my-timeline"></div>
      <div class="story__controls story__controls--row">
        <div class="story__controls__item">
          <label for="heatmap-color-select">Heatmap Color</label>
          <select id="heatmap-color-select" class="select">
            <option value="orange" selected>Single color with alpha</option>
            <option value="sequential">Colors assigned proportionally</option>
            <option value="steps">Colors assigned to event value range</option>
            <option value="type">Colors assigned by event type</option>
            <option value="default">Event color with alpha (default)</option>
          </select>
          <div id="legends"></div>
        </div>
      </div>
    </div>
    <script type="module" src="./code.js"></script>
  </body>
</html>
.story__legend {
  position: absolute;
  background-color: var(--neutral-color700);
  border-radius: var(--s-4);
  padding: var(--s-2);
  right: var(--s0);
  width: max-content;
  height: max-content;
  z-index: 2;
}

.story__legend__row {
  display: flex;
  align-items: center;
}

.story__legend__item {
  height: var(--s0);
  width: var(--s0);
}
.story__legend__text {
  font-size: var(--font-size-about);
  height: var(--s0);
  width: max-content;
  margin-left: var(--s-2);
}
import React, { useState, useRef } from "react";
import { createRoot } from "react-dom/client";
import Timeline from "kronograph/react/Timeline";
import data from "./data";

const colorOptions = {
  default: null,
  // Cells will be colored orange with an alpha value based on the value distribution.
  orange: "orange",
  // Cells will be colored from the given color array based on a percentile distribution of all cell values.
  sequential: ["#dbe2af", "#f3bf5e", "#e89b53", "#cf7047", "#a93e3c", "#7a002d"],
  steps: [
    { value: -1, color: "#fa8072" }, // First value is always ignored, cells default to #fa8072 (red).
    { value: 0, color: "#00a2ed" }, // Cells with values above the threshold of zero will be #00a2ed (blue).
  ],
  type: [
    { eventType: "alert", color: "red" }, // If a cell includes an event with type 'alert', it will be red.
    { eventType: "warning", color: "yellow" }, // If a cell includes an event with type 'warning', it will be yellow.
    { eventType: "default", color: "gray" }, // All other cells will be a gray color.
  ],
};

export const Demo = () => {
  const [heatmapColorKey, setHeatmapColorKey] = useState("orange");
  const [legendPosition, setLegendPosition] = useState(null);
  const timelineRef = useRef(null);

  const options = {
    events: {
      heatmapValue: "amount",
      heatmapThreshold: 20,
      heatmapColor: colorOptions[heatmapColorKey] ?? null,
    },
  };

  function updateLegendPosition() {
    const maxY = Object.keys(timelineRef.current.getInRangeItems().entities).reduce(
      (max, entityName) =>
        Math.max(max, timelineRef.current.getEntityPosition(entityName)?.y2 ?? 0),
      0
    );
    setLegendPosition(maxY + 20);
  }

  return (
    <div className="story">
      <Timeline
        className="story__timeline"
        entities={data.entities}
        ref={timelineRef}
        events={data.events}
        eventTypes={data.eventTypes}
        options={options}
        onTimelineDraw={updateLegendPosition}
      />
      <div className="story__controls story__controls--row">
        <div className="story__controls__item">
          <label htmlFor="heatmap-color-select">Heatmap Color</label>
          <select
            id="heatmap-color-select"
            className="select"
            defaultValue="orange"
            onChange={(e) => {
              setHeatmapColorKey(e.target.value);
            }}
          >
            <option value="orange">Single color with alpha</option>
            <option value="sequential">Colors assigned proportionally</option>
            <option value="steps">Colors assigned to event value range</option>
            <option value="type">Colors assigned by event type</option>
            <option value="default">Event color with alpha (default)</option>
          </select>
        </div>
      </div>
      <Legend legendPosition={legendPosition} heatmapColorKey={heatmapColorKey} />
    </div>
  );
};

const Legend = ({ legendPosition, heatmapColorKey }) => {
  // create legend entries with different alpha values of orange and label them.
  function getOrangeAlphaLegendEntries() {
    const legendEntries = [];
    for (let i = 1; i < 4; i++) {
      const alphaMultiplier = 1 / i;
      const color = `rgb(255,165,0,${alphaMultiplier})`;
      const text = i === 1 ? "Highest amount" : i === 3 ? "Lowest amount" : "";
      legendEntries.push({ color, text });
    }
    return legendEntries;
  }

  // create legend entries for each of the sequential options and label them.
  function getSequentialLegendEntries() {
    return colorOptions.sequential.map((color, i) => {
      return { color, text: `range ${i + 1}` };
    });
  }

  // create legend entries for each of the color steps and label them.
  function getStepsLegendEntries() {
    return colorOptions.steps.map(({ value, color }, i) => {
      const text =
        i === 0 ? `Values up to ${colorOptions.steps[i + 1].value}` : `Values above ${value}`;
      return { color, text };
    });
  }

  // create legend entries for each data type and label them.
  function getTypeLegendEntries() {
    return colorOptions.type.map(({ eventType, color }) => {
      return { color, text: eventType };
    });
  }

  const getLegendEntries = {
    orange: getOrangeAlphaLegendEntries,
    sequential: getSequentialLegendEntries,
    steps: getStepsLegendEntries,
    type: getTypeLegendEntries,
  };

  if (getLegendEntries[heatmapColorKey]) {
    return (
      <div className="story__legend" style={{ top: `${legendPosition}px` }}>
        {getLegendEntries[heatmapColorKey]().map(({ color, text }, i) => (
          <LegendRow color={color} text={text} key={i} />
        ))}
      </div>
    );
  }
  return null;
};

const LegendRow = ({ color, text }) => (
  <div className="story__legend__row">
    <div className="story__legend__item" style={{ backgroundColor: color }}></div>
    <div className="story__legend__text">{text}</div>
  </div>
);

const root = createRoot(document.getElementById("my-timeline"));
root.render(<Demo />);
export default {
  entities: {
    "Aurora Bancorp": {
      color: "#4e79a7",
    },
    "Better Life Bank": {
      color: "#f28e2c",
    },
    "Ace Financial Group": {
      color: "#e15759",
    },
    "Grand Mutual Bank": {
      color: "#76b7b2",
    },
    "Felicity Financial Services": {
      color: "#59a14f",
    },
  },
  events: {
    event0: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: -103,
      },
      time: 1716845042401.983,
      type: "warning",
    },
    event1: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 1522,
      },
      time: 1704300247970.444,
    },
    event2: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 2519,
      },
      time: 1704826361998.4548,
    },
    event3: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 1744,
      },
      time: 1721561387584.9785,
    },
    event4: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 1292,
      },
      time: 1721436187577.0662,
    },
    event5: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 1913,
      },
      time: 1715184891178.0125,
    },
    event6: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 1379,
      },
      time: 1720022197785.7358,
    },
    event7: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Better Life Bank",
      },
      data: {
        amount: 2108,
      },
      time: 1713047293850.0168,
    },
    event8: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 39987,
      },
      time: 1719556922296.1238,
    },
    event9: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 6269,
      },
      time: 1717726178569.1255,
    },
    event10: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 4629,
      },
      time: 1718167137411.861,
    },
    event11: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 4112,
      },
      time: 1719690540773.6128,
    },
    event12: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 44477,
      },
      time: 1718653783292.392,
    },
    event13: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 86674,
      },
      time: 1719055763972.7158,
    },
    event14: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 96953,
      },
      time: 1718812764374.0154,
    },
    event15: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 57831,
      },
      type: "alert",
      time: 1717355969771.8218,
    },
    event16: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: 1992,
      },
      time: 1721029217990.7224,
    },
    event17: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: 471,
      },
      time: 1722545977814.828,
    },
    event18: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: 2274,
      },
      time: 1712785338304.0298,
    },
    event19: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: 3067,
      },
      time: 1706715885813.1304,
    },
    event20: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: -670,
      },
      time: 1705034721408.0198,
    },
    event21: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: -648,
      },
      time: 1719489884462.4038,
    },
    event22: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: 325,
      },
      time: 1721614571235.6663,
    },
    event23: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Ace Financial Group",
      },
      data: {
        amount: 851,
      },
      time: 1705237236251.1895,
    },
    event24: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: 3121,
      },
      time: 1721380170448.32,
    },
    event25: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: -1778,
      },
      time: 1719476838892.334,
    },
    event26: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: 3781,
      },
      time: 1714459016034.4941,
    },
    event27: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: 1165,
      },
      time: 1713136401986.9214,
    },
    event28: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: 2237,
      },
      time: 1712559528845.578,
    },
    event29: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: 1535,
      },
      time: 1720931783679.7734,
    },
    event30: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: -1622,
      },
      time: 1721528143853.7964,
    },
    event31: {
      entityIds: {
        from: "Aurora Bancorp",
        to: "Grand Mutual Bank",
      },
      data: {
        amount: 523,
      },
      time: 1709514478039.349,
    },
    event32: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 1257,
      },
      time: 1715409427247.5706,
    },
    event33: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 736,
      },
      time: 1707482336867.2246,
    },
    event34: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 184,
      },
      time: 1725199319145.929,
    },
    event35: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 1058,
      },
      time: 1713232568113.0273,
    },
    event36: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 1429,
      },
      time: 1721868788309.195,
    },
    event37: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: -5097,
      },
      type: "warning",
      time: 1707839323010.2188,
    },
    event38: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 2522,
      },
      time: 1717712034817.7363,
    },
    event39: {
      entityIds: {
        from: "Better Life Bank",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 3094,
      },
      time: 1724919209625.5513,
    },
    event40: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 1121,
      },
      time: 1718493292818.4546,
    },
    event41: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 2878,
      },
      time: 1714709244615.406,
    },
    event42: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 1504,
      },
      time: 1715372672224.4255,
    },
    event43: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 320,
      },
      time: 1710331215554.826,
    },
    event44: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: 1906,
      },
      time: 1710184345462.6362,
    },
    event45: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: -1246,
      },
      time: 1725198486655.9883,
    },
    event46: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: -1476,
      },
      time: 1706451804586.463,
    },
    event47: {
      entityIds: {
        from: "Ace Financial Group",
        to: "Felicity Financial Services",
      },
      data: {
        amount: -192,
      },
      time: 1723811742494.3857,
    },
  },
  eventTypes: {
    alert: {
      color: "red",
    },
    warning: {
      color: "yellow",
    },
    default: {
      color: "grey",
    },
  },
};
<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="@ci/theme/kg/css/examples.css" />
    <link rel="stylesheet" href="./style.css" />
  </head>
  <body>
    <div id="my-timeline" style="height: 100vh"></div>
    <script type="module" src="./code.jsx"></script>
  </body>
</html>
.story__legend {
  position: absolute;
  background-color: var(--neutral-color700);
  border-radius: var(--s-4);
  padding: var(--s-2);
  right: var(--s0);
  width: max-content;
  height: max-content;
  z-index: 2;
}

.story__legend__row {
  display: flex;
  align-items: center;
}

.story__legend__item {
  height: var(--s0);
  width: var(--s0);
}
.story__legend__text {
  font-size: var(--font-size-about);
  height: var(--s0);
  width: max-content;
  margin-left: var(--s-2);
}

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.