Chart export can be useful for sharing, printing or keeping records of your charts.
In this demo you can adjust the content and size of images to best suit your needs using the extents and fitTo options, and export to a range of common formats.
The chart.export() function can be used to create raster images in high resolution, and vector images in SVG or PDF, preserving the important details of your KeyLines charts in all of the available output types.
For SVG, the export is optimised for viewing at full zoom, ensuring all details are crisp, even on the largest charts.
While here we show how to create a simple PDF with a full page chart image, it is also possible to incorporate charts into more content rich reports with PDF. See our PDF Reports demo for more information.
For further details read our documentation on Chart Export.
Saving image vs. saving chart
This demo saves an image of a chart and does not contain any other information or meta-data about the state of the chart.
If you want to be able to reload the state of the chart, use chart.serialize() as seen in the Save & Load Charts demo.
Key functions used:
import KeyLines from "keylines";
import { data } from "./data.js";
let chart;
let type = "png";
const widthSlider = document.getElementById("widthSlider");
const widthLabel = document.getElementById("widthLabel");
const exportButton = document.getElementById("exportButton");
function initializeUI() {
const typeButtons = {};
function setExportType(newType) {
typeButtons[type].classList.remove("active", "btn-kl");
typeButtons[type].disabled = false;
typeButtons[newType].classList.add("active", "btn-kl");
typeButtons[newType].disabled = true;
type = newType;
widthSlider.disabled = type === "pdf" || type === "svg";
}
function setWidthLabel() {
const width = Math.round(widthSlider.value / 100) / 10;
widthLabel.innerText = `${width}`;
}
["png", "jpeg", "svg", "pdf"].forEach((exportType) => {
typeButtons[exportType] = document.getElementById(exportType);
typeButtons[exportType].addEventListener("click", () =>
setExportType(exportType),
);
});
widthSlider.addEventListener("input", setWidthLabel);
exportButton.addEventListener("click", exportChartImage);
}
function downloadImage(chartImage, format) {
// Create the link to download the image
const snapshotLink = document.createElement("a");
snapshotLink.download = `chart-export.${format}`;
snapshotLink.href = chartImage.url;
snapshotLink.click();
// Important - remember to revoke the url afterwards to free it from browser memory
URL.revokeObjectURL(chartImage.url);
}
async function exportChartImage() {
const extents = document.querySelector(
`input[type="radio"][name="extents"]:checked`,
).value;
let fitTo;
if (type === "pdf") {
// always fit to page for PDF export
fitTo = "page";
} else {
fitTo = {
width:
type === "svg"
? chart.viewOptions().width
: parseInt(widthSlider.value),
};
}
const fonts = {
"Font Awesome 5 Free Solid": {
src: "/fonts/fontAwesome5/fa-solid-900.woff",
},
};
const doc = {
size: "letter",
layout: "landscape",
margin: 36, // 0.5 inches
};
const chartImage = await chart.export({
type,
extents,
fitTo,
// only add fonts for SVG and PDF
...(type === "svg" || type === "pdf" ? { fonts } : {}),
...(type === "pdf" ? { doc } : {}),
});
downloadImage(chartImage, type);
}
// List of icons to realign
const imageAlignment = {
"fas fa-user": { dy: -10, e: 0.9 },
};
async function startKeyLines() {
const options = {
backColour: "rgb(250, 250, 250)",
selectedNode: { b: "#111", bw: 5, fbc: "#333", fc: "white" },
iconFontFamily: "Font Awesome 5 Free",
handMode: true,
logo: { u: "/public/images/Logo.png" },
// Font icons and images can often be poorly aligned.
// Set offsets to the icons to ensure they are centred correctly.
imageAlignment,
};
chart = await KeyLines.create({ container: "klchart", options });
chart.load(data.chartData);
chart.zoom("fit", { animate: false, ids: data.zoomNodes });
initializeUI();
}
async function loadFontsAndStart() {
// be sure to include the CSS file in the page with the @font-face definition
document.fonts.load("24px 'Font Awesome 5 Free'").then(startKeyLines);
}
window.addEventListener("DOMContentLoaded", loadFontsAndStart); export const data = {
chartData: {
type: "LinkChart",
items: [
{
id1: "N1",
id2: "N10",
id: "N1/p/N10",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N1",
id2: "N14",
id: "N1/p/N14",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N1",
id2: "N15",
id: "N1/p/N15",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N1",
id2: "N152",
id: "N1/p/N152",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N1",
id2: "N16",
id: "N1/p/N16",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N1",
id2: "N357",
id: "N1/p/N357",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N1",
id2: "N363",
id: "N1/p/N363",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N1",
id2: "N43",
id: "N1/p/N43",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N1",
id2: "N5",
id: "N1/p/N5",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N1",
id2: "N6",
id: "N1/p/N6",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N1",
id2: "N7",
id: "N1/p/N7",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N1",
id2: "N8",
id: "N1/p/N8",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N10",
id2: "N2",
id: "N10/p/N2",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N10",
id2: "N4",
id: "N10/p/N4",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N10",
id2: "N6",
id: "N10/p/N6",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N104",
id2: "N149",
id: "N104/p/N149",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N104",
id2: "N54",
id: "N104/p/N54",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N107",
id2: "N120",
id: "N107/p/N120",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N108",
id2: "N105",
id: "N108/p/N105",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N108",
id2: "N27",
id: "N108/p/N27",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N108",
id2: "N29",
id: "N108/p/N29",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N109",
id2: "N29",
id: "N109/p/N29",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N11",
id2: "N2",
id: "N11/p/N2",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N11",
id2: "N21",
id: "N11/p/N21",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N11",
id2: "N34",
id: "N11/p/N34",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N11",
id2: "N6",
id: "N11/p/N6",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N110",
id2: "N29",
id: "N110/p/N29",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N112",
id2: "N29",
id: "N112/p/N29",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N115",
id2: "N111",
id: "N115/p/N111",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N115",
id2: "N113",
id: "N115/p/N113",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N117",
id2: "N113",
id: "N117/p/N113",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N118",
id2: "N108",
id: "N118/p/N108",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N12",
id2: "N2",
id: "N12/p/N2",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N12",
id2: "N6",
id: "N12/p/N6",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N120",
id2: "N1",
id: "N120/p/N1",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N124",
id2: "N126",
id: "N124/p/N126",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N125",
id2: "N126",
id: "N125/p/N126",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N13",
id2: "N2",
id: "N13/p/N2",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N13",
id2: "N21",
id: "N13/p/N21",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N13",
id2: "N23",
id: "N13/p/N23",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N13",
id2: "N25",
id: "N13/p/N25",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N13",
id2: "N34",
id: "N13/p/N34",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N13",
id2: "N6",
id: "N13/p/N6",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N138",
id2: "N142",
id: "N138/p/N142",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N140",
id2: "N139",
id: "N140/p/N139",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N141",
id2: "N143",
id: "N141/p/N143",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N141",
id2: "N147",
id: "N141/p/N147",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N141",
id2: "N148",
id: "N141/p/N148",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N147",
id2: "N148",
id: "N147/p/N148",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N149",
id2: "N54",
id: "N149/p/N54",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N151",
id2: "N195",
id: "N151/p/N195",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N153",
id2: "N155",
id: "N153/p/N155",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N153",
id2: "N167",
id: "N153/p/N167",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N153",
id2: "N175",
id: "N153/p/N175",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N153",
id2: "N179",
id: "N153/p/N179",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N153",
id2: "N195",
id: "N153/p/N195",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N153",
id2: "N196",
id: "N153/p/N196",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N154",
id2: "N1",
id: "N154/p/N1",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N154",
id2: "N41",
id: "N154/p/N41",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N154",
id2: "N43",
id: "N154/p/N43",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N155",
id2: "N161",
id: "N155/p/N161",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N155",
id2: "N175",
id: "N155/p/N175",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N155",
id2: "N180",
id: "N155/p/N180",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N156",
id2: "N151",
id: "N156/p/N151",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N156",
id2: "N152",
id: "N156/p/N152",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N156",
id2: "N167",
id: "N156/p/N167",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N156",
id2: "N175",
id: "N156/p/N175",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N156",
id2: "N191",
id: "N156/p/N191",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N157",
id2: "N153",
id: "N157/p/N153",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N157",
id2: "N158",
id: "N157/p/N158",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N158",
id2: "N161",
id: "N158/p/N161",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N161",
id2: "N167",
id: "N161/p/N167",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N161",
id2: "N175",
id: "N161/p/N175",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N161",
id2: "N179",
id: "N161/p/N179",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N161",
id2: "N195",
id: "N161/p/N195",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N161",
id2: "N196",
id: "N161/p/N196",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N165",
id2: "N156",
id: "N165/p/N156",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N166",
id2: "N173",
id: "N166/p/N173",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N166",
id2: "N175",
id: "N166/p/N175",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N174",
id2: "N180",
id: "N174/p/N180",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N175",
id2: "N179",
id: "N175/p/N179",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N175",
id2: "N195",
id: "N175/p/N195",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N175",
id2: "N196",
id: "N175/p/N196",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N175",
id2: "N6",
id: "N175/p/N6",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N177",
id2: "N180",
id: "N177/p/N180",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N178",
id2: "N173",
id: "N178/p/N173",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N184",
id2: "N153",
id: "N184/p/N153",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N185",
id2: "N153",
id: "N185/p/N153",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N19",
id2: "N355",
id: "N19/p/N355",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N196",
id2: "N151",
id: "N196/p/N151",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N2",
id2: "N21",
id: "N2/p/N21",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N2",
id2: "N26",
id: "N2/p/N26",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N2",
id2: "N27",
id: "N2/p/N27",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N2",
id2: "N30",
id: "N2/p/N30",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N2",
id2: "N33",
id: "N2/p/N33",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N2",
id2: "N357",
id: "N2/p/N357",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N2",
id2: "N5",
id: "N2/p/N5",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N2",
id2: "N6",
id: "N2/p/N6",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N2",
id2: "N8",
id: "N2/p/N8",
c: "rgb(150,150,150)",
type: "link",
w: 1,
off: 0,
g: null,
},
{
id1: "N202",
id2: "N306",
id: "N202/p/N306",
c: "rgb(150,150,150)",
type: "link",
// ...truncated 18533 lines <!doctype html>
<html lang="en" style="background-color: #2d383f">
<head>
<meta charset="utf-8" />
<title>Export Chart</title>
<link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/keylines.css" />
<link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/minimalsdk.css" />
<link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/sdk-layout.css" />
<link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/demo.css" />
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div id="klchart" class="klchart"></div>
<script src="pdfkit/js/pdfkit.standalone.js" defer type="text/javascript"></script>
<script src="svg-to-pdfkit" defer type="text/javascript"></script>
<script type="module" src="./code.js"></script>
</body>
</html> .klchart {
background-color: rgb(250, 250, 250);
}
.sliderGroup {
width: 100%;
height: 40px;
}
.sliderScale {
float: left;
line-height: 10px;
padding: 5px;
}
.sliderContainer {
float: left;
width: calc(100% - 200px);
}
#imageWidthSlider {
margin: 10px;
width: calc(100% - 20px);
}