alpha-version-dce-check-in-ui
Version:
UI for taking attendance and checking people in.
155 lines (131 loc) • 4.71 kB
text/typescript
// Import QR generator
import QRCode from 'qrcode';
/*------------------------------------------------------------------------*/
/* ------------------------------ Constants ----------------------------- */
/*------------------------------------------------------------------------*/
/*----------------------------------------*/
/* ---------- Adjustable Params --------- */
/*----------------------------------------*/
// Width of generated image
const WIDTH_PX = 800;
// Card styling
const BACKGROUND_COLOR = '#A41034'; // Harvard Crimson
const WIDTH_TO_HEIGHT_RATIO = 1.2;
const CARD_BORDER_RADIUS_RATIO = 0.06;
// Text styling
const TEXT_COLOR = 'white';
const TEXT = 'Scan to Check In';
const TEXT_SIZE_RATIO = 0.11;
const TEXT_TO_TOP_BORDER_RATIO = 0.1;
// QR code styling
const CARD_TO_QR_CODE_WIDTH_RATIO = 0.85;
const QR_BORDER_RADIUS_RATIO = 0.04;
/*----------------------------------------*/
/* ---- Dynamically-generated Params ---- */
/*----------------------------------------*/
// Don't customize the look here, these are based on params above
// Canvas size
const canvasWidth = WIDTH_PX * window.devicePixelRatio;
const canvasHeight = canvasWidth * WIDTH_TO_HEIGHT_RATIO;
// Card size and location
const cardWidth = WIDTH_PX;
const cardHeight = WIDTH_TO_HEIGHT_RATIO * WIDTH_PX;
const cardRadius = CARD_BORDER_RADIUS_RATIO * WIDTH_PX;
// Text size and location
const textFontSize = TEXT_SIZE_RATIO * WIDTH_PX;
const textX = WIDTH_PX / 2;
const textY = TEXT_TO_TOP_BORDER_RATIO * WIDTH_PX;
// Sub-text size and location
const subTextFontSize = textFontSize / 1.6;
const subTextX = textX;
const subTextY = 2 * textY;
// QR code size and location
const qrWidth = WIDTH_PX * CARD_TO_QR_CODE_WIDTH_RATIO;
const qrX = WIDTH_PX * (1 - CARD_TO_QR_CODE_WIDTH_RATIO) / 2;
const qrY = (WIDTH_PX * WIDTH_TO_HEIGHT_RATIO) - qrX - (WIDTH_PX * CARD_TO_QR_CODE_WIDTH_RATIO) + (TEXT_TO_TOP_BORDER_RATIO * WIDTH_PX / 5.25);
const qrRadius = QR_BORDER_RADIUS_RATIO * WIDTH_PX;
/*------------------------------------------------------------------------*/
/* ---------------------------- QR Generator ---------------------------- */
/*------------------------------------------------------------------------*/
/**
* Create a QR code card, with specified text, QR code value, and background color.
* Could be made server-side via the node-canvas package
* @author Benedikt Arnarsson
* @author Gabe Abrams
* @param value the URL which the QR code will hold
* @returns the dataURL representing the QR card image
*/
const getQrCardImg = async (value: string, subText=''): Promise<string> => {
// Create invisible canvas
// Reference: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#non-null-assertion-operator
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d')!;
context.canvas.hidden = true;
// Configure canvas size
// See SO: https://stackoverflow.com/a/65124939
canvas.width = canvasWidth;
canvas.height = canvasHeight;
context.scale(window.devicePixelRatio, window.devicePixelRatio);
// Card background
context.beginPath();
context.fillStyle = BACKGROUND_COLOR;
context.roundRect(
0,
0,
cardWidth,
cardHeight,
cardRadius,
);
context.stroke();
context.fill();
// QR background
context.beginPath();
context.fillStyle = 'white';
context.strokeStyle = 'white';
context.roundRect(qrX, qrY, qrWidth, qrWidth, qrRadius);
context.stroke();
context.fill();
// Text
context.font = `bold ${textFontSize}px arial`;
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillStyle = TEXT_COLOR;
context.fillText(TEXT, textX, textY);
// Sub-text
const formattedSubText = (
subText.length >= 15
? `${subText.substring(0, 15)}...`
: subText
);
context.font = `bold ${subTextFontSize}px arial`;
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillStyle = TEXT_COLOR;
context.fillText(formattedSubText, subTextX, subTextY);
// QR code
// > Generate QR code image
const qrCodeDataURL = await QRCode.toDataURL(
value,
{
width: qrWidth,
margin: 2,
color: {
light: '#ffffff00', // white, fully transparent
},
},
);
// > Convert to HTML Image
const qrImg = new Image();
qrImg.src = qrCodeDataURL;
// > Wait for image to process/load
await new Promise((resolve) => {
qrImg.onload = resolve;
});
// > Draw image to canvas
context.drawImage(qrImg, qrX, qrY, qrWidth, qrWidth);
// Return data URL and destroy canvas
const qrCard = canvas.toDataURL();
canvas.remove();
return qrCard;
};
export default getQrCardImg;