Cluedo Detective Notes
I made a pdf of Cluedo Detective Notes which you can download from here. Although it has 16 pages, you don’t need to print all of them. Just print out the number of pages you actually need.
In order to create this file I piggy backed of a private web app that I have been building which uses “PDF Kit”.
For reference the source code of the parts of PDF kit that do this are as follows:-
Firstly the main production text. This first function is loaded by an api server serving the request. params.position
is
a tweek to determing how many pages to print via a labeling system that we were piggy backing off to allow user selection. You
can see how limit
is calculated as it prints 4 detective notes per page. doc
is the result of calling
doc = new PDFModules.Label(res)
where res
is the http response
(function() {
'use strict';
module.exports = async function( params, doc) {
doc.info.Title = 'Cleudo Labels ';
doc.options.margins = { top: 28, bottom: 28, left: 28, right: 28 }
let position = 0;
const limit = (params.position + 1) * 4;
for(let i= 0; i < limit; i++) {
position = doc.labelContext('four', position);
doc.font('Helvetica-Bold').fontSize(12);
doc.text('D', 40, 10 ,{continued: true , baseline: 'alphabetic'}).fontSize(10).text('ETECTIVE',{continued:true})
.fontSize(12).text(' N', {continued: true}).fontSize(10).text('OTES');
doc.text('Suspected Persons',0,30 ).moveDown(0.8);
doc.font('Helvetica').text('Col Mustard').text('Prof Plum').text('Rev Green').text('Mrs Peacock').text('Miss Scarlett').text('Mrs White');
doc.moveDown(1.5).font('Helvetica-Bold').text('Probable Implements').moveDown(0.8);
doc.font('Helvetica').text('Dagger').text('Candlestick').text('Revolver').text('Rope').text('Lead Piping').text('Spanner');
doc.moveDown(1.5).font('Helvetica-Bold').text('Suspected Scene of Murder').moveDown(0.8);
doc.font('Helvetica').text('Hall').text('Lounge').text('Dining Room').text('Kitchen').text('Ball Room').text('Conservatory');
doc.text('Billiard Room').text('Library').text('Study');
doc.labelContextReset();
}
};
})();
Then the control file that defined how the “labels” are laid out on the page
(function() {
'use strict';
module.exports = {
four: {
initialX: 28.35,
initialY: 28.35,
deltaX: 297.68,
deltaY: 421.00,
width: 221.74,
columns: 2,
rows: 2
}
};
})();
And then the bit of the main pdf control function that uses that control file to repeadely output the single detective note at the correct part of the page
(function() {
'use strict';
const label = require('../config/label');
const PDFKit = require('pdfkit');
const margins = { top: 36, bottom: 36, left: 72, right: 72 }
class PDFDocument extends PDFKit {
constructor(response, layout) {
const options = {
size: 'A4',
layout: layout ?? 'landscape',
info: info,
margins: margins
}
super(options);
this.pipe(response);
this.font('Helvetica', 11); //default initial font
}
}
class Label extends PDFDocument {
constructor(response) {
super(response, 'portrait')
this.labelDepth = false;
}
labelContext(type, position) {
let params = label[type];
if (params === undefined) {
throw new Error('Invalid Label Type');
}
if (this.labelDepth) {
throw new Error('Label Context not clear');
}
this.labelDepth = true;
let inPage = position % (params.rows * params.columns);
if (position > 0 && inPage === 0) {
this.addPage();
}
let column = inPage % params.columns;
let row = Math.floor(inPage / params.columns);
this.save(); // save context so we can restore it
//eslint-disable-next-line max-len
this.translate(params.initialX + (column * params.deltaX), params.initialY + (row * params.deltaY));
return position + 1;
}
labelContextReset() {
if (!this.labelDepth) {
throw new Error('Label Context Not Set');
}
this.restore();
this.labelDepth = false;
}
}
module.exports = {
PDFDocument: PDFDocument,
Label: Label
};
})();