Run Cystoscape.js with Node.js

stereobooster - Oct 19 '23 - - Dev Community

Why? If you need to generate an image on the server side.

At first, I thought it was impossible. There is cytosnap that uses Puppeteer (headless browser). Then, for fun, I rewrote it with Tauri.

But later, I though, what if it would be possible to run it with Node.js. And, indeed, it’s possible.

Solution

Add polyfils for the browser (it also includes canvas):

class XMLSerializer {
 serializeToString(node) {
 return serialize(node);
 }
}
global.XMLSerializer = XMLSerializer;

const dom = new JSDOM(`<!DOCTYPE html><div id="cy"></div>`);
global.window = dom.window;
global.document = dom.window.document;
Enter fullscreen mode Exit fullscreen mode

Explicitly set bounding box

source.layout.boundingBox = {
 x1: 0,
 y1: 0,
 x2: source.width,
 y2: source.height,
};
Enter fullscreen mode Exit fullscreen mode

Generate a graph the same way you would in the browser:

const container = dom.window.document.querySelector("#cy");
const cy = cytoscape({ container, ...defaults, ...source });
cy.layout(source.layout).run();
Enter fullscreen mode Exit fullscreen mode

For now I was able to render it only as SVG:

await loadExtension("svg");
res = cy.svg({
 bg: source.background,
 full: true,
});
Enter fullscreen mode Exit fullscreen mode

In order to not polute global scope with polyfills we can run this script as sub-process:

const executablePath = `bin/cyto-nodejs.js`;
const bin = spawn(executablePath, args, {
 windowsHide: true,
});
Enter fullscreen mode Exit fullscreen mode

That’s it.

Source code

Source code is here: https://github.com/stereobooster/cyto-nodejs

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .