Create an E-Book Reader Challenge

The main challenge in rendering the text into fixed container slides lies in calculating the appropriate points to split the text into pages, so I needed to come up with a strategy for page breaking.

My initial idea was to detect the on-screen space occupied by each letter and divide the entire text into an array of page blocks. However, this approach has complications: in fonts that are not monospaced, each letter occupies a different amount of space, making it overly complex and inefficient to measure every letter in various fonts and sizes.

Therefore, I decided to identify the first word on each new page. To simplify the process, let's temporarily set aside styling elements like headings for a while and imagine a scenario where we deal exclusively with plain text:

I divided the entire text into an array of individual words, rendering each word separately to identify the first word of each new page. Subsequently, I saved the indexes of these first words in an array named breakpoints

Now, let's bring back styles. Headings and body text will not share the same line. So, I parsed the input text line by line and converted it into an array of objects like this:

const contentBlocks = [
    { style: "heading": words: ["Prins"] },
    { style: "body": words: ["Mijn", "moeder", "is", "zevenenzeventig"] },
    ...
    ...
]

As a result of these changes, the breakpoints are updated accordingly:

Given the breakpoints consisting of line indexes along with word indexes, it becomes straightforward to write a function that will return a chunk of the array of contentBlocks for a given page index.

type BreakPoint = string // 1:15
type ContentBlock = Array<{ style: string; words: string[] }>

function getPageBlocksByBreakPoint(contentBlocks: ContentBlocks, start: BreakPoint, End: BreakPoint): ContentBlocks

Graph

Problems

Rendering the entire 300-page book directly into the DOM for detecting page breaks would indeed be highly resource-intensive, particularly in terms of memory usage. Therefore, it's essential to optimize the algorithm to address this challenge.

Also, resizing the container size, font size, font style, or even a change in the font type, would require re-generating breakPoints

Links

šŸ”— See Demo at https://ebook-reader.gegia.dev

šŸ”— See GitHub Repository

Published on March 6, 2024