• Stars
    star
    972
  • Rank 45,233 (Top 1.0 %)
  • Language
    JavaScript
  • License
    BSD 2-Clause "Sim...
  • Created over 12 years ago
  • Updated 11 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

TeX line breaking algorithm in JavaScript

TeX line breaking algorithm in JavaScript

This is an implementation of the Knuth and Plass line breaking algorithm using JavaScript. The goal of this project is to optimally set justified text in the browser, and ultimately provide a library for various line breaking algorithms in JavaScript.

The paragraph below is set using a JavaScript implementation of the classic Knuth and Plass algorithm as used in TeX. The numbers on the right of each line are the stretching or shrinking ratio compared to the optimal line width. This example uses a default space of 1/3 em, with a stretchability and shrink-ability of 1/6 em and 1/9 em respectively.

The following paragraph is set by a browser using text-align: justify. Notice the lines in the paragraph have, on average, greater inter-word spacing than the Knuth and Plass version, which is successful at minimizing the inter-word spacing over all lines.

The browser also ends up with ten lines instead of the nine lines found by the Knuth and Plass line breaking algorithm. This comparison might not be completely fair since we don't know the default inter-word space used by the browser (nor its stretching and shrinking parameters.) Experimental results however indicate the values used in most browsers are either identical or very similar. The next section explains how the ratio values for the browser were calculated.

Measuring the quality of browser line breaks

Unfortunately there is no API to retrieve the positions of the line breaks the browser inserted, so we'll have to resort to some trickery. By wrapping each word in an invisible <span> element and retrieving its y position we can find out when a new line starts. If the y position of the current word is different from the previous word we know a new line has started. This way a paragraph is split up in several individual lines.

The ratios are then calculated by measuring the difference between the width of each line when text-align is set to justify and when it is set to left. This difference is then divided by the amount of stretchability of the line: i.e. the number of spaces multiplied by the stretch width for spaces. Although we don't know the actual stretchability we can use 1/6 em, just like the Knuth and Plass algorithm, if we only use it for comparison.

Assisted browser line breaks

The line breaking algorithm can also be used to correct the line breaks made by the browser. The easiest way to do is to split a text up into lines and adjust the CSS word-spacing property. Unfortunately, Webkit based browsers do not support sub-pixel word-spacing. Alternatively, we can absolute position each word or split the line into segmants with integer word spacing. You can see the latter approach in action on the Flatland line breaking example.

Examples

The line breaking algorithm is not only capable of justifying text, it can perform all sorts of alignment with an appropriate selection of boxes, glue and penalties. It is also possible to give it varying line widths to flow text around illustrations, asides or quotes. Alternatively, varying line widths can be used to create interesting text shapes as demonstrated below.

Ragged right and centered alignment

The following example is set ragged right. Ragged right is not simply justified text with fixed width inter-word spacing. Instead the algorithm tries to minimize the amount of white space at the end of each sentence over the whole paragraph. It also attempts to reduce the number of words that are "sticking out" of the margin.

Ragged left text can be achieved by using a ragged right text and aligning its line endings with the left border. The example below is set centered. Again this is not simply a centering of justified text, but instead an attempt at minimizing the line lengths over the whole paragraph.

Variable line width

By varying the line width for a paragraph it is possible to flow the text around illustrations, asides, quotes and such. The example below leaves a gap for an illustration by setting the line widths temporarily shorter and then reverting. You can also see that the algorithm chose to hyphenate certain words to achieve acceptable line breaking.

It is also possible to make some non-rectangular shapes, as shown in the examples below. In the first example, the text is laid out using an increasing line width and center aligning each line. This creates a triangular shape.

Using some basic math it is also possible to set text in circles or even arbitrary polygons. Below is an example of text set inside a circle.

To-do

The following are some extensions to the algorithm discussed in the original paper, which I intend to implement (at some point.)

  • Hanging punctuation. The following quote from the original paper explains how to implement it using the box, glue and penalty model:

    Some people prefer to have the right edge of their text look β€˜solid’, by setting periods, commas, and other punctuation marks (including inserted hyphens) in the right-hand margin. For example, this practice is occasionally used in contemporary advertising.

    It is easy to get inserted hyphens into the margin: We simply let the width of the corresponding penalty item be zero. And it is almost as easy to do the same for periods and other symbols, by putting every such character in a box of width zero and adding the actual symbol width to the glue that follows. If no break occurs at this glue, the accumulated width is the same as before; and if a break does occur, the line will be justified as if the period or other symbol were not present.

  • Compare quality against line-breaking implemented by Internet Explorer's text-justify CSS property.

  • Figure out how to deal with dynamic paragraphs (i.e. paragraphs being edited) as their ratios will change during editing and thus visibly move around.

References

These are the resources I found most useful while implementing the line breaking algorithm.

More Repositories

1

fontfaceobserver

Webfont loading. Simple, small, and efficient.
JavaScript
4,215
star
2

hypher

A fast and small JavaScript hyphenation engine
JavaScript
561
star
3

trmix

apply CSS based on your browser's text rendering engine
JavaScript
499
star
4

homebrew-webfonttools

Homebrew formulae for font tools
Ruby
359
star
5

fontloader

A fontloader polyfill
JavaScript
324
star
6

xsltjson

XSLTJSON - Convert XML to JSON using XSLT
XSLT
302
star
7

jlayout

JavaScript layout algorithms
JavaScript
283
star
8

funcy

An experiment in adding functional pattern matching to JavaScript
JavaScript
246
star
9

url-template

A JavaScript URI template implementation (RFC 6570 compliant)
JavaScript
179
star
10

opentype

An OpenType, TrueType, WOFF, and WOFF2 parser in JavaScript
JavaScript
133
star
11

sfnt2woff-zopfli

WOFF utilities with Zopfli compression
C
122
star
12

promis

A small embeddable Promise polyfill
JavaScript
97
star
13

postcss-scale

PostCSS plugin to scale values from one range to another.
HTML
80
star
14

bit-array

JavaScript implementation of bit arrays.
JavaScript
78
star
15

hyphenation-patterns

Hyphenation patterns for use with Hypher
JavaScript
74
star
16

stateofwebtype

Up-to-date data on support for type and typographic features on the web.
JavaScript
64
star
17

junify

JUnify ― JavaScript Unification Library
JavaScript
48
star
18

text-overflow

jQuery Text Overflow plugin
JavaScript
43
star
19

jsizes

jQuery CSS size properties plugin
JavaScript
37
star
20

characterset

A library for creating and manipulating character sets
JavaScript
29
star
21

css-font-parser

A parser for the CSS font values
JavaScript
26
star
22

jslint

JSLint: The JavaScript Quality Tool, command line version (Node.js)
JavaScript
25
star
23

datrie

A JavaScript Double Array Trie
JavaScript
21
star
24

unicode-tokenizer

Unicode Tokenizer following the Unicode Line Breaking algorithm
JavaScript
20
star
25

node-typekit

A minimal Typekit API client in Node.js
JavaScript
19
star
26

nanofont

A nano font for testing font format support
Makefile
19
star
27

knockout.selection

A selection binding for Knockout.js
JavaScript
19
star
28

javascript

Various JavaScript projects & tools.
JavaScript
17
star
29

knockout.dragdrop

A HTML5 drag and drop binding for Knockout.
JavaScript
16
star
30

text-align

jQuery Text Alignment plugin
JavaScript
13
star
31

tpo

Next generation of browser typesetting
JavaScript
13
star
32

closure-compiler-inline

A Closure Compiler fork with more control over function inlining
Java
11
star
33

calcdeps

A Node.js port of Google Closure library calcdeps.py
JavaScript
11
star
34

js-preprocess

JavaScript Preprocessor
JavaScript
9
star
35

column-selector

jQuery Column Selector
JavaScript
9
star
36

fonzie

A tiny @font-face loader
JavaScript
8
star
37

phantomjs-typekit

A simple demo of using Typekit with PhantomJS
JavaScript
8
star
38

epub2ts

ePub to Treesaver conversion
JavaScript
8
star
39

php-typekit

A PHP client for the Typekit API
PHP
7
star
40

shp2json

Simple tool to convert Shapefiles (GIS) to JSON
JavaScript
6
star
41

nanoserver

A simple web server for development
JavaScript
5
star
42

emfont

A font with a single character filling the entire em-box
HTML
5
star
43

jslint-core

JSLint: The JavaScript Code Quality Tool packaged as a CommonJS module
JavaScript
5
star
44

ui

C++/OpenGL User Interface library
5
star
45

hyphenation-justification-vf

JavaScript
4
star
46

node-browserstack

A Node.js client for the BrowserStack API (v3 and screenshot)
JavaScript
4
star
47

sfnt2woff

C
4
star
48

mocha-browserstack

A Mocha reporter that can be used to run Mocha tests automatically on BrowserStack
JavaScript
4
star
49

website

bramstein.com website source
JavaScript
3
star
50

unicode-data-parser

JavaScript
3
star
51

markup

JavaScript
2
star
52

closure-dom

JavaScript
2
star
53

ui-test

C++/OpenGL User Interface library test project
2
star
54

closureloader

Load code using the Closure library dependency syntax in Node.js
JavaScript
2
star
55

cssvalue

Parsers (and generators) for common CSS values.
JavaScript
2
star
56

thesis

Master Thesis: "Visualizations on the Web"
2
star
57

sowt-test

Automated browser tests for State of Web Type
JavaScript
2
star
58

closure-fetch

JavaScript
1
star
59

detect-writing-script

Detect the writing script given an array of codepoints.
JavaScript
1
star
60

ui-demo

C++/OpenGL User Interface library demo
1
star
61

font-weight-test

Test case for font-weight fallback behaviour
Makefile
1
star
62

amd-to-closure

Transform AMD modules to Closure Compiler dependencies
JavaScript
1
star
63

fontformatdetection

Detect browser support for font formats using feature detection
JavaScript
1
star