//
//     Copyright © 2011-2025 Cambridge Intelligence Limited.
//     All rights reserved.
//
//     Sample Code
//
//!    Find communities in your network.
import KeyLines from "keylines";
import { data } from "./clusters-data.js";

let chart;

const clustersSlider = document.getElementById("clustersSlider");

// Generate a random hex colour
function randomColour() {
  return `#${`${Math.random().toString(16)}0000000`.slice(2, 8)}`;
}

// Generate a new colour for each cluster:
// for each colour created save it inside an array:
// this works well with the stability factor of the cluster algo
const coloursList = [];

function getColour(i) {
  // Cache a colour list and generate a new colour if not already present.
  if (!coloursList[i]) {
    coloursList[i] = randomColour();
  }
  return coloursList[i];
}

function runClusters() {
  // Don't bother running unless the value has changed
  const newValue = clustersSlider.value;

  // Update the label
  document.getElementById("clustersVal").innerText = newValue;

  // Get the clusters - a 2d array of nodes
  const result = chart.graph().clusters({
    factor: newValue,
    consistent: true,
  });
  // Get the changes - the first array is of groups, with the contents being the nodes in each
  // group. As we're looking for changes, we use flatMap to go through all groups and merge
  // them into a single array.
  const changes = [];
  result.forEach((inner, k1) => {
    inner.forEach((id) => {
      changes.push({ id, c: getColour(k1) });
    });
  });
  // Apply the changes
  chart.setProperties(changes);
}

async function startKeyLines() {
  const options = {
    logo: { u: "/images/Logo.png" },
    linkEnds: { avoidLabels: false },
    handMode: true,
  };

  chart = await KeyLines.create({
    container: "klchart",
    options,
  });

  chart.load(data);

  clustersSlider.addEventListener("input", runClusters);

  chart.zoom("fit");
  runClusters();
}

window.addEventListener("DOMContentLoaded", startKeyLines);
<!DOCTYPE html>
<html lang="en" style="background-color: #2d383f;">
  <head>
    <meta charset="UTF-8">
    <title>Clusters</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="/clusters.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="/clusters.js" crossorigin="use-credentials" 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="klchart">
          </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%;">Clusters</text>
          </svg>
        </div>
        <div class="tab-content-panel" data-tab-group="rhs">
          <div class="toggle-content is-visible tabcontent" id="controlsTab">
            <p>Adjust the slider below to group nodes based on the size of their cluster and colour these groups accordingly.</p>
            <form autocomplete="off" onsubmit="return false" id="rhsForm">
              <div class="cicontent control-group" id="clusterControlGroup">
                <legend>Clusters factor: <strong class="lead" id="clustersVal">5</strong></legend>
                <div class="sliderGroup">
                  <div class="sliderScale">0</div>
                  <div class="sliderContainer">
                    <input id="clustersSlider" type="range" min="0" max="10" value="5">
                  </div>
                  <div class="sliderScale">10</div>
                </div>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
    <div id="moreParent">
      <div id="moreContainer">
      </div>
    </div>
    <div id="lazyScripts">
    </div>
  </body>
</html>
.sliderScale {
  float: left;
  line-height: 33px;
}

.sliderContainer {
  float: left;
  width: calc(100% - 30px);
}

#clustersSlider {
  margin: 10px;
  width: calc(100% - 20px);
}
Loading source