//
//     Copyright © 2011-2025 Cambridge Intelligence Limited.
//     All rights reserved.
//
//     Sample Code
//
//!    See how to use multiple link shapes in your chart.
import KeyLines from "keylines";
import { comboIds, data } from "./mixedlinkshapes-data.js";

const customiseInComboCheckbox = document.getElementById("customise-in-combos");

let chart;

function getLinkShapeForColour(colour) {
  return document.querySelector(`#${colour}-link-shape-btn-group .active`)
    .value;
}

function setLinkShapes() {
  const shape = {
    red: getLinkShapeForColour("red"),
    green: getLinkShapeForColour("green"),
    blue: getLinkShapeForColour("blue"),
  };
  const setOnChildLinks = customiseInComboCheckbox.checked;
  const linkShapesToSet = [];
  chart.each({ type: "link", items: "all" }, (l) => {
    if (!l.parentId || setOnChildLinks) {
      linkShapesToSet.push({
        id: l.id,
        linkShape: { name: shape[l.d.colour] },
      });
    } else {
      linkShapesToSet.push({ id: l.id, linkShape: null });
    }
  });
  chart.setProperties(linkShapesToSet);
}

async function layout() {
  await chart.layout("sequential", {
    orientation: "right",
    stretchType: "auto",
  });
}

// Modify the default combo double click behavior so that
// it still toggles the open state of the combo, but disables
// push-pull and runs a new layout instead
async function onDoubleClick({ id, preventDefault, button }) {
  if (!id || button !== 0) {
    return;
  }

  const comboApi = chart.combo();
  const combo = comboApi.isCombo(id) ? id : chart.getItem(id).parentId;

  if (combo) {
    const opts = { adapt: "none" };
    preventDefault();
    if (comboApi.isOpen(combo)) {
      await comboApi.close(combo, opts);
    } else {
      await comboApi.open(combo, opts);
    }
    await layout();
  }
}

function initialiseInteractions() {
  const shapeByColourButtons = document.querySelectorAll(
    ".link-shape-btn-group button"
  );
  shapeByColourButtons.forEach((button) => {
    button.addEventListener("click", () => {
      const colour = button.dataset.colour;
      const currentSelection = document.querySelector(
        `#${colour}-link-shape-btn-group .active`
      );
      const currentShape = currentSelection.value;
      if (button.value !== currentShape) {
        currentSelection.classList.remove("active");
        button.classList.add("active");
        setLinkShapes();
      }
    });
  });
  customiseInComboCheckbox.addEventListener("change", setLinkShapes);

  // perform layout on combo open/close
  chart.on("double-click", onDoubleClick);
}

async function startKeyLines() {
  const options = {
    handMode: true,
    combos: { shape: "rectangle" },
    defaultStyles: { openCombos: { borderRadius: 10 } },
  };

  chart = await KeyLines.create({ container: "klchart", options });
  await chart.load(data);
  setLinkShapes();
  await chart.combo().open(comboIds);
  await chart
    .combo()
    .arrange(comboIds, {
      name: "sequential",
      orientation: "right",
      linkShape: "curved",
    });
  await layout();

  initialiseInteractions();
}

window.addEventListener("DOMContentLoaded", startKeyLines);
<!DOCTYPE html>
<html lang="en" style="background-color: #2d383f;">
  <head>
    <meta charset="UTF-8">
    <title>Mixed Link Shapes</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="mixedlinkshapes.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/webfontloader.js" defer type="text/javascript"></script>
    <script src="/mixedlinkshapes.js" crossorigin="use-credentials" 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="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%;">Mixed Link Shapes</text>
          </svg>
        </div>
        <div class="tab-content-panel" data-tab-group="rhs">
          <div class="toggle-content is-visible tabcontent" id="controlsTab">
            <p>Select a link shape for each set of coloured links. Choose whether they override the combo link shape, which is set to 'curved'.</p>
            <form autocomplete="off" onsubmit="return false" id="rhsForm">
              <div class="cicontent">
                <fieldset>
                  <legend>Link Shape Customisation</legend>
                  <div class="btn-row">
                    <p>Red</p>
                    <div class="link-shape-btn-group btn-group" id="red-link-shape-btn-group">
                      <button class="btn btn-kl" type="button" data-colour="red" value="direct">Direct</button>
                      <button class="btn btn-kl active" type="button" data-colour="red" value="curved">Curved</button>
                      <button class="btn btn-kl" type="button" data-colour="red" value="angled">Angled</button>
                    </div>
                  </div>
                  <div class="btn-row">
                    <p>Green</p>
                    <div class="link-shape-btn-group btn-group" id="green-link-shape-btn-group">
                      <button class="btn btn-kl active" type="button" data-colour="green" value="direct">Direct</button>
                      <button class="btn btn-kl" type="button" data-colour="green" value="curved">Curved</button>
                      <button class="btn btn-kl" type="button" data-colour="green" value="angled">Angled</button>
                    </div>
                  </div>
                  <div class="btn-row">
                    <p>Blue</p>
                    <div class="link-shape-btn-group btn-group" id="blue-link-shape-btn-group">
                      <button class="btn btn-kl" type="button" data-colour="blue" value="direct">Direct</button>
                      <button class="btn btn-kl" type="button" data-colour="blue" value="curved">Curved</button>
                      <button class="btn btn-kl active" type="button" data-colour="blue" value="angled">Angled</button>
                    </div>
                  </div>
                  <label class="checkbox inline">
                    <input id="customise-in-combos" type="checkbox">Apply customised link shapes within combos
                  </label>
                </fieldset>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
    <div id="moreParent">
      <div id="moreContainer">
      </div>
    </div>
    <div id="lazyScripts">
    </div>
  </body>
</html>
.btn-row {
  display: flex;
  margin: 8px 0px;
}

.btn-row p {
  text-align: right;
  padding: 8px;
  width: 64px;
}

.btn-group .btn:hover {
  color: white;
}

#red-link-shape-btn-group .btn.active {
  background-color: #dd3c3c;
  border-color: #dd3c3c;
}
#red-link-shape-btn-group .btn:hover {
  background-color: #F15D5B;
  border-color: #F15D5B;
}
#green-link-shape-btn-group .btn.active {
  background-color: #048170;
  border-color: #048170;
}
#green-link-shape-btn-group .btn:hover {
  background-color: #2DCDA8;
  border-color: #2DCDA8;
}
#blue-link-shape-btn-group .btn.active {
  background-color: #3377FF;
  border-color: #3377FF;
}
#blue-link-shape-btn-group .btn:hover {
  background-color: #6699FF;
  border-color: #6699FF;
}
Loading source