Skip to content
This repository was archived by the owner on Jul 1, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"docs": "d3plus-docs",
"env": "d3plus-env",
"release": "d3plus-release",
"test": "eslint src test && mocha 'test/**/*-test.js'"
"test": "eslint src test && mocha 'test/**/*-test.js'",
"prepare": "yarn build"
},
"devDependencies": {
"d3plus-dev": "^1.2.9"
Expand Down
127 changes: 68 additions & 59 deletions src/textWrap.js
Original file line number Diff line number Diff line change
@@ -1,167 +1,176 @@
import measure from "./textWidth.js";
import defaultSplit from "./textSplit.js";
import stringify from "./stringify.js";
import {trimRight} from "./trim.js";
import measure from './textWidth.js';
import defaultSplit from './textSplit.js';
import stringify from './stringify.js';
import { trimRight } from './trim.js';

/**
@function textWrap
@desc Based on the defined styles and dimensions, breaks a string into an array of strings for each line of text.
*/
export default function() {

let fontFamily = "sans-serif",
fontSize = 10,
fontWeight = 400,
height = 200,
lineHeight,
maxLines = null,
overflow = false,
split = defaultSplit,
width = 200;
export default function () {
let fontFamily = 'sans-serif',
fontSize = 10,
fontWeight = 400,
height = 200,
lineHeight,
maxLines = null,
overflow = false,
split = defaultSplit,
width = 200;

/**
The inner return object and wraps the text and returns the line data array.
@private
*/
function textWrap(sentence) {

sentence = stringify(sentence);

if (lineHeight === void 0) lineHeight = Math.ceil(fontSize * 1.4);

const words = split(sentence);

const style = {
"font-family": fontFamily,
"font-size": fontSize,
"font-weight": fontWeight,
"line-height": lineHeight
'font-family': fontFamily,
'font-size': fontSize,
'font-weight': fontWeight,
'line-height': lineHeight,
};

let line = 1,
textProg = "",
truncated = false,
widthProg = 0;
textProg = '',
truncated = false,
widthProg = 0;

const lineData = [],
sizes = measure(words, style),
space = measure(" ", style);
sizes = measure(words, style),
space = measure(' ', style);

for (let i = 0; i < words.length; i++) {
let word = words[i];
const wordWidth = sizes[words.indexOf(word)];
word += sentence.slice(textProg.length + word.length).match("^( |\n)*", "g")[0];
if (textProg.slice(-1) === "\n" || widthProg + wordWidth > width) {
if (!i && !overflow) {
truncated = true;
break;
word += sentence
.slice(textProg.length + word.length)
.match('^( |\n)*', 'g')[0];

if (
i === 0 ||
textProg.slice(-1) === '\n' ||
widthProg + wordWidth > width
) {
if (i > 0) {
if (lineData.length >= line) {
lineData[line - 1] = trimRight(lineData[line - 1]);
}
line++;
}
if (lineData.length >= line) lineData[line - 1] = trimRight(lineData[line - 1]);
line++;
if (lineHeight * line > height || wordWidth > width && !overflow || maxLines && line > maxLines) {

if (lineHeight * line > height || (maxLines && line > maxLines)) {
truncated = true;
break;
}
widthProg = 0;

widthProg = wordWidth;

lineData.push(word);
} else {
lineData[line - 1] += word;
widthProg += wordWidth;
}
else if (!i) lineData[0] = word;
else lineData[line - 1] += word;

textProg += word;
widthProg += wordWidth;
widthProg += word.match(/[\s]*$/g)[0].length * space;
console.log('\n');
}

return {
lines: lineData,
sentence, truncated,
sentence,
truncated,
widths: measure(lineData, style),
words
words,
};

}

/**
@memberof textWrap
@desc If *value* is specified, sets the font family accessor to the specified function or string and returns this generator. If *value* is not specified, returns the current font family.
@param {Function|String} [*value* = "sans-serif"]
*/
textWrap.fontFamily = function(_) {
return arguments.length ? (fontFamily = _, textWrap) : fontFamily;
textWrap.fontFamily = function (_) {
return arguments.length ? ((fontFamily = _), textWrap) : fontFamily;
};

/**
@memberof textWrap
@desc If *value* is specified, sets the font size accessor to the specified function or number and returns this generator. If *value* is not specified, returns the current font size.
@param {Function|Number} [*value* = 10]
*/
textWrap.fontSize = function(_) {
return arguments.length ? (fontSize = _, textWrap) : fontSize;
textWrap.fontSize = function (_) {
return arguments.length ? ((fontSize = _), textWrap) : fontSize;
};

/**
@memberof textWrap
@desc If *value* is specified, sets the font weight accessor to the specified function or number and returns this generator. If *value* is not specified, returns the current font weight.
@param {Function|Number|String} [*value* = 400]
*/
textWrap.fontWeight = function(_) {
return arguments.length ? (fontWeight = _, textWrap) : fontWeight;
textWrap.fontWeight = function (_) {
return arguments.length ? ((fontWeight = _), textWrap) : fontWeight;
};

/**
@memberof textWrap
@desc If *value* is specified, sets height limit to the specified value and returns this generator. If *value* is not specified, returns the current value.
@param {Number} [*value* = 200]
*/
textWrap.height = function(_) {
return arguments.length ? (height = _, textWrap) : height;
textWrap.height = function (_) {
return arguments.length ? ((height = _), textWrap) : height;
};

/**
@memberof textWrap
@desc If *value* is specified, sets the line height accessor to the specified function or number and returns this generator. If *value* is not specified, returns the current line height accessor, which is 1.1 times the [font size](#textWrap.fontSize) by default.
@param {Function|Number} [*value*]
*/
textWrap.lineHeight = function(_) {
return arguments.length ? (lineHeight = _, textWrap) : lineHeight;
textWrap.lineHeight = function (_) {
return arguments.length ? ((lineHeight = _), textWrap) : lineHeight;
};

/**
@memberof textWrap
@desc If *value* is specified, sets the maximum number of lines allowed when wrapping.
@param {Function|Number} [*value*]
*/
textWrap.maxLines = function(_) {
return arguments.length ? (maxLines = _, textWrap) : maxLines;
textWrap.maxLines = function (_) {
return arguments.length ? ((maxLines = _), textWrap) : maxLines;
};

/**
@memberof textWrap
@desc If *value* is specified, sets the overflow to the specified boolean and returns this generator. If *value* is not specified, returns the current overflow value.
@param {Boolean} [*value* = false]
*/
textWrap.overflow = function(_) {
return arguments.length ? (overflow = _, textWrap) : overflow;
textWrap.overflow = function (_) {
return arguments.length ? ((overflow = _), textWrap) : overflow;
};

/**
@memberof textWrap
@desc If *value* is specified, sets the word split function to the specified function and returns this generator. If *value* is not specified, returns the current word split function.
@param {Function} [*value*] A function that, when passed a string, is expected to return that string split into an array of words to textWrap. The default split function splits strings on the following characters: `-`, `/`, `;`, `:`, `&`
*/
textWrap.split = function(_) {
return arguments.length ? (split = _, textWrap) : split;
textWrap.split = function (_) {
return arguments.length ? ((split = _), textWrap) : split;
};

/**
@memberof textWrap
@desc If *value* is specified, sets width limit to the specified value and returns this generator. If *value* is not specified, returns the current value.
@param {Number} [*value* = 200]
*/
textWrap.width = function(_) {
return arguments.length ? (width = _, textWrap) : width;
textWrap.width = function (_) {
return arguments.length ? ((width = _), textWrap) : width;
};

return textWrap;

}