Skip to content

Commit b2ca830

Browse files
committed
feat(typography): add PRETTY/BALANCE textWrap modes with DP-based balanced wrapping
- Adds PRETTY and BALANCE constants to src/core/constants.js - Implements dynamic programming algorithm in _lineate for balanced line breaking - Minimizes raggedness by considering all possible line breaks - Includes manual test demonstrating PRETTY/BALANCE vs WORD wrap Addresses #7712
1 parent 514df2a commit b2ca830

File tree

4 files changed

+111
-0
lines changed

4 files changed

+111
-0
lines changed

src/core/constants.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,18 @@ export const CHAR = 'CHAR';
10721072
* @final
10731073
*/
10741074
export const WORD = 'WORD';
1075+
/**
1076+
* @typedef {'PRETTY'} PRETTY
1077+
* @property {PRETTY} PRETTY
1078+
* @final
1079+
*/
1080+
export const PRETTY = 'PRETTY';
1081+
/**
1082+
* @typedef {'BALANCE'} BALANCE
1083+
* @property {BALANCE} BALANCE
1084+
* @final
1085+
*/
1086+
export const BALANCE = 'BALANCE';
10751087

10761088
// TYPOGRAPHY-INTERNAL
10771089
export const _DEFAULT_TEXT_FILL = '#000000';

src/type/textCore.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2387,6 +2387,48 @@ function textCore(p5, fn) {
23872387
opts = {}
23882388
) {
23892389

2390+
// Handle PRETTY/BALANCE with DP algorithm
2391+
if (textWrap === fn.PRETTY || textWrap === fn.BALANCE) {
2392+
let newLines = [];
2393+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
2394+
const wordsArr = lines[lineIndex].split(' ').filter(s => s.length > 0);
2395+
const spaceW = this._textWidthSingle(' ');
2396+
const N = wordsArr.length;
2397+
const widths = wordsArr.map(s => this._textWidthSingle(s));
2398+
2399+
// DP arrays
2400+
const dp = new Array(N + 1).fill(Infinity);
2401+
const next = new Array(N + 1).fill(-1);
2402+
dp[N] = 0;
2403+
2404+
// DP algorithm to minimize raggedness
2405+
for (let i = N - 1; i >= 0; i--) {
2406+
let sum = 0;
2407+
for (let j = i; j < N; j++) {
2408+
sum += widths[j];
2409+
const gaps = j - i;
2410+
const total = sum + gaps * spaceW;
2411+
if (total > maxWidth) break;
2412+
const slack = maxWidth - total;
2413+
const cost = (j === N - 1 ? 0 : slack * slack) + dp[j + 1];
2414+
if (cost < dp[i]) {
2415+
dp[i] = cost;
2416+
next[i] = j + 1;
2417+
}
2418+
}
2419+
}
2420+
2421+
// Reconstruct lines
2422+
let i = 0;
2423+
while (i < N) {
2424+
const j = next[i] > 0 ? next[i] : i + 1;
2425+
newLines.push(wordsArr.slice(i, j).join(' '));
2426+
i = j;
2427+
}
2428+
}
2429+
return newLines;
2430+
}
2431+
23902432
let splitter = opts.splitChar ?? (textWrap === fn.WORD ? ' ' : '');
23912433
let line, testLine, testWidth, words, newLines = [];
23922434

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
function setup() {
2+
createCanvas(800, 600);
3+
background(255);
4+
5+
let sampleText = 'This is a sample text that will be wrapped using the new PRETTY and BALANCE modes. It should result in more balanced line lengths compared to standard WORD wrapping.';
6+
let boxWidth = 200;
7+
let boxHeight = 150;
8+
9+
// Test 1: WORD wrap (standard)
10+
fill(0);
11+
textSize(16);
12+
textAlign(LEFT, TOP);
13+
textWrap(WORD);
14+
15+
stroke(200);
16+
noFill();
17+
rect(50, 50, boxWidth, boxHeight);
18+
19+
fill(0);
20+
noStroke();
21+
text('WORD wrap:', 50, 30);
22+
text(sampleText, 50, 50, boxWidth, boxHeight);
23+
24+
// Test 2: PRETTY wrap
25+
stroke(200);
26+
noFill();
27+
rect(300, 50, boxWidth, boxHeight);
28+
29+
fill(0);
30+
noStroke();
31+
textWrap(PRETTY);
32+
text('PRETTY wrap:', 300, 30);
33+
text(sampleText, 300, 50, boxWidth, boxHeight);
34+
35+
// Test 3: BALANCE wrap (alias for PRETTY)
36+
stroke(200);
37+
noFill();
38+
rect(550, 50, boxWidth, boxHeight);
39+
40+
fill(0);
41+
noStroke();
42+
textWrap(BALANCE);
43+
text('BALANCE wrap:', 550, 30);
44+
text(sampleText, 550, 50, boxWidth, boxHeight);
45+
46+
noLoop();
47+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>PRETTY/BALANCE TextWrap Test</title>
5+
<script src="../../../dist/p5.js"></script>
6+
<script src="pretty-sketch.js"></script>
7+
</head>
8+
<body>
9+
</body>
10+
</html>

0 commit comments

Comments
 (0)