Skip to main content

Add some line breaking logic

ID
2ecb25d
date
2025-01-25 23:30:01+00:00
author
Alex Chan <alex@alexwlchan.net>
parent
289f96d
message
Add some line breaking logic
changed files
1 file, 101 additions, 77 deletions

Changed files

static/app.js (9219 → 9626)

diff --git a/static/app.js b/static/app.js
index d9a19be..fd45996 100644
--- a/static/app.js
+++ b/static/app.js
@@ -195,15 +195,19 @@ function createCoverImage(ficInfo) {
   // Add the author name.
   ctx.font = '65px Georgia';
   
-  if (ficInfo.length > 35) {
-    ctx.fillText(ficInfo.author.slice(0, 17), width / 2, height * 0.85);
-    ctx.fillText(ficInfo.author.slice(17, 35) + '…', width / 2, height * 0.85 + 80);
-  } else if (ficInfo.author.length > 15) {
-    ctx.fillText(ficInfo.author.slice(0, 17), width / 2, height * 0.85);
-    ctx.fillText(ficInfo.author.slice(17, 35), width / 2, height * 0.85 + 80);
-  } else {
-    ctx.fillText(ficInfo.author, width / 2, height * 0.85);
-  }
+  const { lines: authorLines, separator } = getAuthorLines({
+    ctx, authorName: ficInfo.author, maxWidth: width * 0.75
+  });
+  
+  drawLinesOfText({
+    ctx,
+    width,
+    lines: authorLines,
+    separator,
+    maxLines: 2,
+    lineStart: height * 0.85,
+    lineHeight: 77,
+  });
   
   // Add the title.
   //
@@ -214,25 +218,19 @@ function createCoverImage(ficInfo) {
   // to indicate it's been truncated.
   ctx.font = '95px Georgia';
   
-  var lines = getTitleLines({
-    ctx, title: ficInfo.title, maxWidth: width * 0.8,
+  const titleLines = getTitleLines({
+    ctx, title: ficInfo.title, maxWidth: width * 0.75,
+  });
+  
+  drawLinesOfText({
+    ctx,
+    width,
+    lines: titleLines,
+    separator: " ",
+    maxLines: 5,
+    lineStart: height * 0.2,
+    lineHeight: 112,
   });
-    
-  if (lines.length > 5) {
-    lines = lines.slice(0, 5);
-    lines[4] = lines[4] + '…'
-  }
-    
-  const lineHeight = 100;
-  const titleStart = height * 0.2;
-    
-  for (i = 0; i < lines.length; i++) {
-    ctx.fillText(
-      lines[i],
-      width / 2,
-      titleStart + i * lineHeight
-    );
-  }
   
   return canvas;
 }
@@ -267,7 +265,7 @@ function getLinesForWords({ ctx, words, maxWidth, separator }) {
     // Remember to add a line for anything not already tracked.
     lines.push(currentLine);
     
-    return lines;
+    return { lines, separator };
 }
 
 
@@ -276,9 +274,11 @@ function getLinesForWords({ ctx, words, maxWidth, separator }) {
  * Split a title into lines to fit into a <canvas> without wrapping.
  */
 function getTitleLines({ ctx, title, maxWidth }) {
-    return getLinesForWords({
-        ctx, words: title.split(" "), maxWidth, separator: " "
-    });
+  const { lines } = getLinesForWords({
+    ctx, words: title.split(" "), maxWidth, separator: " "
+  });
+    
+  return lines;
 }
 
 
@@ -292,54 +292,78 @@ function getTitleLines({ ctx, title, maxWidth }) {
  * We only have room for two lines of text in the author name, so
  * anything beyond that gets truncated.
  */
-function getAuthorLines(ctx, authorName, maxWidth) {
+function getAuthorLines({ ctx, authorName, maxWidth }) {
   
-    // If the author name includes any spaces, assume we have a list
-    // of space separated words we can use.
-    if (authorName.includes(' ')) {
-        return getLinesForWords({
-            ctx, words: authorName.split(" "), maxWidth, separator: " "
-        });
-    }
-    
-    // Another common convention is to use underscores, in which
-    // case we can split on that.
-    else if (authorName.includes('_')) {
-        return getLinesForWords({
-            ctx, words: authorName.split("_"), maxWidth, separator: "_"
-        });
-    }
-    
-    // Another common convention is to use intercaps, e.g. JaneSmith,
-    // so we can split on those words if we need to.
-    else if (/[A-Z]/.test(authorName)) {
-        return getLinesForWords({
-            ctx,
-            words: authorName.replace(/([A-Z])/g, ' $1').trim().split(/\s+/),
-            maxWidth,
-            separator: ""
-        });
-    }
-    
-    // Otherwise, we just break the string into individual characters
-    // and fit as many as we can onto each line.
-    else {
-        return getLinesForWords({
-            ctx,
-            words: [...authorName],
-            maxWidth,
-            separator: ""
-        });
-    }
+  // If the author name includes any spaces, assume we have a list
+  // of space separated words we can use.
+  if (authorName.includes(' ')) {
+    return getLinesForWords({
+      ctx, words: authorName.split(" "), maxWidth, separator: " "
+    });
+  }
+  
+  // Another common convention is to use underscores, in which
+  // case we can split on that.
+  else if (authorName.includes('_')) {
+    return getLinesForWords({
+      ctx, words: authorName.split("_"), maxWidth, separator: "_"
+    });
+  }
+  
+  // Another common convention is to use intercaps, e.g. JaneSmith,
+  // so we can split on those words if we need to.
+  else if (/[A-Z]/.test(authorName)) {
+    return getLinesForWords({
+      ctx,
+      words: authorName.replace(/([A-Z])/g, ' $1').trim().split(/\s+/),
+      maxWidth,
+      separator: ""
+    });
+  }
+  
+  // Otherwise, we just break the string into individual characters
+  // and fit as many as we can onto each line.
+  else {
+    return getLinesForWords({
+      ctx,
+      words: [...authorName],
+      maxWidth,
+      separator: ""
+    });
+  }
 }
 
 
 
-if (typeof module !== 'undefined') {
-  module.exports = {
-    chooseColour,
-    createCoverImage,
-    findContentOpfPath,
-    getFicInfo,
-  };
-}
+
+/**
+ * Add lines of text to a canvas.
+ *
+ * The text will be drawn in the middle of the page.
+ */
+function drawLinesOfText({ ctx, width, lines, separator, maxLines, lineStart, lineHeight }) {
+  
+  // If there are more lines than we can fit, truncate to that length
+  // and add an ellipsis.
+  if (lines.length > maxLines) {
+    lines = lines.slice(0, maxLines);
+    lines[maxLines - 1] += '…';
+  }
+  
+  console.log(lines);
+  
+  // Got through and add the lines of text we're drawing.  Depending
+  // on the separator, we may need to add a hyphen or similar to
+  // indicate line continuation.
+  for (lineno = 0; lineno < lines.length; lineno++) {
+    const thisLine = lines[lineno];
+    
+    const displayLine =
+      separator === " " ? thisLine
+        : separator === "_" ? thisLine + "_"
+        : lineno < lines.length - 1 ? thisLine + "-"
+        : thisLine;
+    
+    ctx.fillText(displayLine, width / 2, lineStart + lineno * lineHeight);
+  }
+}
\ No newline at end of file