Skip to content

Instantly share code, notes, and snippets.

@thepatrickniyo
Created January 10, 2025 10:48
Show Gist options
  • Save thepatrickniyo/912e9a6e1cc6a7e4cdb0d3d6ac1999a8 to your computer and use it in GitHub Desktop.
Save thepatrickniyo/912e9a6e1cc6a7e4cdb0d3d6ac1999a8 to your computer and use it in GitHub Desktop.
/**
* Prints text with support for bold sections (marked with **) and automatic line breaks
* @param {object} doc - The PDF document object
* @param {number} startY - The starting Y position
* @param {string} text - The input text with ** marking bold sections
* @param {object} options - Additional options for formatting
* @param {number} options.pageMargin - Page margin (default: 40)
* @param {number} options.innerPadding - Inner padding (default: 10)
* @param {number} options.lineSpacing - Spacing between lines (default: 10)
* @param {number} options.fontSize - Font size (default: 10)
* @param {number} options.pageWidth - Width of the page (default: 595)
*/
interface LineSegment {
text: string;
isBold: boolean;
x: number;
}
// Define types for better type safety
interface FormattedTextOptions {
pageMargin?: number;
innerPadding?: number;
lineSpacing?: number;
fontSize?: number;
pageWidth?: number;
}
interface LineSegment {
text: string;
isBold: boolean;
x: number;
}
/**
* Prints text with support for bold sections (marked with **) and automatic line breaks
* @param doc - The PDF document object
* @param startY - The starting Y position
* @param text - The input text with ** marking bold sections
* @param options - Additional options for formatting
* @returns The final Y position after printing
*/
export function printFormattedText(
doc: Record<string, any>,
startY: number,
text: string,
options: FormattedTextOptions
): number {
// Default values
const PAGE_MARGIN = options.pageMargin || 40;
const INNER_PADDING = options.innerPadding || 10;
const LINE_SPACING = options.lineSpacing || 6; // Reduced from 10 to 6
const FONT_SIZE = options.fontSize || 10;
const PAGE_WIDTH = options.pageWidth || 595;
// Calculate maximum width for text
const bodyMaxWidth = PAGE_WIDTH - (2 * PAGE_MARGIN) - (2 * INNER_PADDING);
// Set initial font properties
doc.setFontSize(FONT_SIZE);
doc.setFont("helvetica", "normal");
// Split text into bold and normal sections
const textSegments = text.split('**');
// Current position tracking
let currentX = PAGE_MARGIN + INNER_PADDING;
let currentY = startY;
let lineSegments: LineSegment[] = [];
// Process each text segment
textSegments.forEach((segment, index) => {
if (!segment) return; // Skip empty segments
// Determine if this segment should be bold
const isBold = index % 2 === 1;
// Split segment into words
const words = segment.split(' ');
words.forEach((word, wordIndex) => {
// Add space before word (except for first word)
const wordWithSpace = wordIndex === 0 ? word : ' ' + word;
// Set font for measurement
doc.setFont("helvetica", isBold ? "bold" : "normal");
const wordWidth = doc.getTextWidth(wordWithSpace);
// Check if adding this word would exceed the line width
if (currentX + wordWidth > PAGE_MARGIN + INNER_PADDING + bodyMaxWidth) {
// Print current line
printLine(doc, lineSegments, currentY);
// Reset for new line
currentY += LINE_SPACING;
currentX = PAGE_MARGIN + INNER_PADDING;
lineSegments = [];
}
// Add word to current line segments
lineSegments.push({
text: wordWithSpace,
isBold,
x: currentX
});
currentX += wordWidth;
});
});
// Print any remaining text
if (lineSegments.length > 0) {
printLine(doc, lineSegments, currentY);
}
// Return the final Y position
return currentY;
}
/**
* Helper function to print a single line with mixed bold/normal text
*/
function printLine(doc: Record<string, any>, segments: LineSegment[], currentY: number): void {
segments.forEach(segment => {
doc.setFont("helvetica", segment.isBold ? "bold" : "normal");
doc.text(segment.text, segment.x, currentY, {align: 'left'});
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment