Skip to content

Instantly share code, notes, and snippets.

@jmerle
Created February 24, 2019 13:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jmerle/cfe83b11607f524bcb63fb14a6e37201 to your computer and use it in GitHub Desktop.
Save jmerle/cfe83b11607f524bcb63fb14a6e37201 to your computer and use it in GitHub Desktop.
Export the GitKraken tree to a png image
/**
* Save the visible part of the GitKraken tree to a png file.
*
* Instructions:
* 1. Start GitKraken with the `--remote-debugging-port=9222` argument and wait for the tree to show
* 2. Open Chrome and go to `http://localhost:9222/`
* 3. Click on the GitKraken link and go to the Console tab
* 4. Copy-paste the script down below and wait until it logs the image file path
* 5. Reload GitKraken (Ctrl+R) because the script messes up the view in order to create a neat screenshot
*
* Known issues:
* - The max height of the resulting image is 32767px (which shows around 1100 commits). This is because
* we stitch images together using a canvas which (on Chrome) can be max 32767px high.
*/
(async () => {
const { remote, webFrame } = require('electron');
const fs = require('fs');
const os = require('os');
const path = require('path');
const maxHeight = 32767;
const container = '.graph-container';
const list = document.querySelector(`${container} .graph-panel:nth-child(3)`);
const { scrollHeight } = list;
const visibleHeight = parseInt(list.style.height.split('px')[0]);
function loadScript(src) {
return new Promise((resolve, reject) => {
const el = document.createElement('script');
el.src = src;
el.onload = resolve;
el.onerror = reject;
const scheme = src.split('://')[0];
webFrame.registerURLSchemeAsBypassingCSP(scheme);
document.head.appendChild(el);
});
}
function formatNumber(x) {
return x < 9 ? '0' + x : x;
}
function getImagePath() {
const now = new Date();
const year = now.getFullYear();
const month = formatNumber(now.getMonth() + 1);
const day = formatNumber(now.getDate());
const hour = formatNumber(now.getHours());
const minute = formatNumber(now.getMinutes());
const second = formatNumber(now.getSeconds());
const dateSuffix = `${year}${month}${day}-${hour}${minute}${second}`;
return path.resolve(os.homedir(), `gitkraken-tree-${dateSuffix}.png`);
}
function removeClass(cls) {
const nodes = [...document.querySelectorAll(`${container} .${cls}`)];
nodes.forEach(node => node.classList.remove(cls));
}
function beautifyTree() {
[
'is-selected',
'horizontal_scrollbar',
'vertical_scrollbar',
].forEach(removeClass);
[
...document.querySelectorAll('.commit-zone .absolute.top-0.bottom-0.z3'),
].forEach(node => node.remove());
document.querySelector('.toolbar .upper').style.boxShadow = 'none';
}
function takeScreenshot() {
return new Promise(async resolve => {
beautifyTree();
await new Promise(resolve => setTimeout(resolve, 50));
const bounds = document.querySelector(container).getBoundingClientRect();
const options = {
x: Math.round(bounds.left),
y: Math.round(bounds.top),
width: Math.round(bounds.width),
height: Math.round(bounds.height),
};
remote.webContents.getAllWebContents()[0].capturePage(options, image => {
resolve(image);
});
});
}
async function getImageAtY(y) {
list.scrollTop = y;
await new Promise(resolve => setTimeout(resolve, 50));
const image = await takeScreenshot();
return {
src: image.toDataURL(),
x: 0,
y: list.scrollTop,
};
}
await loadScript('https://unpkg.com/merge-images@1.1.0/dist/index.umd.js');
const images = [];
for (let y = 0; y < maxHeight - visibleHeight && y < scrollHeight; y += visibleHeight) {
images.push(await getImageAtY(y));
}
images.push(await getImageAtY(scrollHeight - visibleHeight));
const base64 = await mergeImages(images, {
height: Math.min(scrollHeight, maxHeight),
});
const imageData = base64.replace(/^data:image\/png;base64,/, '');
const imagePath = getImagePath();
fs.writeFile(imagePath, imageData, { encoding: 'base64' }, err => {
if (err) {
console.error('Something went wrong while saving the tree');
console.error(err);
} else {
console.log(`Saved the tree to ${imagePath}`);
}
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment