dont wrap when its smaller than a single word.

This commit is contained in:
inssein 2015-06-11 20:00:23 -07:00
parent 079a6f4e30
commit 26bba123af
2 changed files with 92 additions and 67 deletions

View file

@ -12,7 +12,7 @@
var t = transform.target;
if (t instanceof fabric.Textbox) {
var w = t.width * ((localMouse.x / transform.scaleX) / (t.width + t.strokeWidth));
if (w >= t.minWidth) {
if (w >= t.getMinWidth()) {
t.set('width', w);
}
}
@ -46,11 +46,11 @@
* @private
*/
_removeExtraneousStyles: function () {
//for (var prop in this._styleMap) {
// if (!this._textLines[prop]) {
// delete this.styles[this._styleMap[prop].line];
// }
//}
for (var prop in this._styleMap) {
if (!this._textLines[prop]) {
delete this.styles[this._styleMap[prop].line];
}
}
},
/**
@ -139,13 +139,13 @@
removeStyleObject: function (isBeginningOfLine, index) {
var cursorLocation = this.get2DCursorLocation(index),
map = this._styleMap[cursorLocation.lineIndex],
lineIndex = map.line,
charIndex = map.offset + cursorLocation.charIndex;
map = this._styleMap[cursorLocation.lineIndex],
lineIndex = map.line,
charIndex = map.offset + cursorLocation.charIndex;
if (isBeginningOfLine) {
var textOnPreviousLine = this._getTextOnPreviousLine(cursorLocation.lineIndex),
newCharIndexOnPrevLine = textOnPreviousLine ? textOnPreviousLine.length : 0;
var textOnPreviousLine = this._getTextOnPreviousLine(cursorLocation.lineIndex),
newCharIndexOnPrevLine = textOnPreviousLine ? textOnPreviousLine.length : 0;
if (!this.styles[lineIndex - 1]) {
this.styles[lineIndex - 1] = {};

View file

@ -25,6 +25,12 @@
* @default
*/
minWidth: 20,
/**
* Minimum calculated width of a textbox, in pixels.
* @type Number
* @default
*/
dynamicMinWidth: 0,
/**
* Cached array of text wrapping.
* @type Array
@ -53,6 +59,7 @@
// add width to this list of props that effect line wrapping.
this._dimensionAffectingProps.width = true;
},
/**
* Unlike superclass's version of this function, Textbox does not update
* its width.
@ -69,17 +76,32 @@
ctx = fabric.util.createCanvasElement().getContext('2d');
this._setTextStyles(ctx);
}
// clear dynamicMinWidth as it will be different after we re-wrap line
this.dynamicMinWidth = 0;
// wrap lines
this._textLines = this._splitTextIntoLines();
// if after wrapping, the width is smaller than dynamicMinWidth, change the width and re-wrap
if(this.dynamicMinWidth > this.width) {
this._set('width', this.dynamicMinWidth);
}
// calculate a styleMap that lets us know where styles as, as _textLines is separated by \n and wraps,
// but the style object line indices is by \n.
this._styleMap = this._generateStyleMap();
// clear cache and re-calculate height
this._clearCache();
this.height = this._getTextHeight(ctx);
},
_generateStyleMap: function() {
var realLineCount = 0,
_generateStyleMap: function () {
var realLineCount = 0,
realLineCharCount = 0,
charCount = 0,
map = {};
charCount = 0,
map = {};
for (var i = 0; i < this._textLines.length; i++) {
if (this.text[charCount] === '\n') {
@ -88,7 +110,7 @@
realLineCount++;
}
map[i] = { line: realLineCount, offset: realLineCharCount };
map[i] = {line: realLineCount, offset: realLineCharCount};
charCount += this._textLines[i].length;
realLineCharCount += this._textLines[i].length;
@ -103,17 +125,17 @@
* @param {Boolean} [returnCloneOrEmpty=false]
* @private
*/
_getStyleDeclaration: function(lineIndex, charIndex, returnCloneOrEmpty) {
if(this._styleMap) {
_getStyleDeclaration: function (lineIndex, charIndex, returnCloneOrEmpty) {
if (this._styleMap) {
var map = this._styleMap[lineIndex];
lineIndex = map.line;
charIndex = map.offset + charIndex;
}
if(returnCloneOrEmpty) {
if (returnCloneOrEmpty) {
return (this.styles[lineIndex] && this.styles[lineIndex][charIndex])
? clone(this.styles[lineIndex][charIndex])
: { };
: {};
}
return this.styles[lineIndex] && this.styles[lineIndex][charIndex] ? this.styles[lineIndex][charIndex] : null;
@ -125,7 +147,7 @@
* @param {Object} style
* @private
*/
_setStyleDeclaration: function(lineIndex, charIndex, style) {
_setStyleDeclaration: function (lineIndex, charIndex, style) {
var map = this._styleMap[lineIndex];
lineIndex = map.line;
charIndex = map.offset + charIndex;
@ -138,7 +160,7 @@
* @param {Number} charIndex
* @private
*/
_deleteStyleDeclaration: function(lineIndex, charIndex) {
_deleteStyleDeclaration: function (lineIndex, charIndex) {
var map = this._styleMap[lineIndex];
lineIndex = map.line;
charIndex = map.offset + charIndex;
@ -150,7 +172,7 @@
* @param {Number} lineIndex
* @private
*/
_getLineStyle: function(lineIndex) {
_getLineStyle: function (lineIndex) {
var map = this._styleMap[lineIndex];
return this.styles[map.line];
},
@ -160,7 +182,7 @@
* @param {Object} style
* @private
*/
_setLineStyle: function(lineIndex, style) {
_setLineStyle: function (lineIndex, style) {
var map = this._styleMap[lineIndex];
this.styles[map.line] = style;
},
@ -169,7 +191,7 @@
* @param {Number} lineIndex
* @private
*/
_deleteLineStyle: function(lineIndex) {
_deleteLineStyle: function (lineIndex) {
var map = this._styleMap[lineIndex];
delete this.styles[map.line];
},
@ -214,7 +236,9 @@
ctx.restore();
}
else {
width += this._applyCharStylesGetWidth(ctx, text[i], lineIndex, i);
// @note: we intentionally pass in an empty style declaration, because if we pass in nothing, it will
// retry fetching style declaration
width += this._applyCharStylesGetWidth(ctx, text[i], lineIndex, i, {});
}
}
@ -230,44 +254,31 @@
* to.
*/
_wrapLine: function (ctx, text, lineIndex) {
var maxWidth = this.width, words = text.split(' '),
lines = [],
line = '';
var maxWidth = this.width,
words = text.split(' '),
lines = [],
line = '',
offset = 0,
lineWidth = this._measureText(ctx, text, lineIndex, offset);
var offset = 0;
// if the current line fits, do nothing
if (lineWidth < maxWidth) {
// if the current line is only one word, we need to keep track of it if it's a large word
if (text.indexOf(' ') === -1 && lineWidth > this.dynamicMinWidth) {
this.dynamicMinWidth = lineWidth;
}
if (this._measureText(ctx, text, lineIndex, offset) < maxWidth) {
lines.push(text);
}
else {
var largestWordWidth = 0,
wordWidth = 0;
while (words.length > 0) {
wordWidth = this._measureText(ctx, words[0], lineIndex, line.length + offset);
lineWidth = line === '' ? wordWidth : this._measureText(ctx, line + words[0], lineIndex, offset);
/*
* If the textbox's width is less than the widest letter.
* TODO: Performance improvement - cache the width of W whenever
* fontSize changes.
*/
if (maxWidth <= ctx.measureText('W').width) {
return text.split('');
}
/*
* This handles a word that is longer than the width of the
* text area.
*/
while (Math.ceil(this._measureText(ctx, words[0], lineIndex, offset)) >= maxWidth) {
var tmp = words[0];
words[0] = tmp.slice(0, -1);
if (words.length > 1) {
words[1] = tmp.slice(-1) + words[1];
}
else {
words.push(tmp.slice(-1));
}
}
if (Math.ceil(this._measureText(ctx, line + words[0], lineIndex, offset)) < maxWidth) {
if (Math.ceil(lineWidth) < maxWidth || Math.ceil(wordWidth) >= maxWidth) {
line += words.shift() + ' ';
}
else {
@ -279,6 +290,15 @@
if (words.length === 0) {
lines.push(line.substring(0, line.length - 1));
}
// keep track of largest word
if (wordWidth > largestWordWidth) {
largestWordWidth = wordWidth;
}
}
if (largestWordWidth > this.dynamicMinWidth) {
this.dynamicMinWidth = largestWordWidth;
}
}
@ -330,13 +350,13 @@
selectionStart = this.selectionStart;
}
var numLines = this._textLines.length,
removed = 0,
textHasChanged = this.__text !== this.text;
var numLines = this._textLines.length,
removed = 0,
textHasChanged = this.__text !== this.text;
for (var i = 0; i < numLines; i++) {
var line = this._textLines[i],
lineLen = line.length;
var line = this._textLines[i],
lineLen = line.length;
if (selectionStart <= removed + lineLen) {
// edge case:
@ -375,11 +395,11 @@
* @returns {Object} Object with 'top', 'left', and 'lineLeft' properties set.
*/
_getCursorBoundariesOffsets: function (chars, typeOfBoundaries) {
var topOffset = 0,
leftOffset = 0,
cursorLocation = this.get2DCursorLocation(),
lineChars = this._textLines[cursorLocation.lineIndex].split(''),
lineLeftOffset = this._getCachedLineOffset(cursorLocation.lineIndex);
var topOffset = 0,
leftOffset = 0,
cursorLocation = this.get2DCursorLocation(),
lineChars = this._textLines[cursorLocation.lineIndex].split(''),
lineLeftOffset = this._getCachedLineOffset(cursorLocation.lineIndex);
for (var i = 0; i < cursorLocation.charIndex; i++) {
leftOffset += this._getWidthOfChar(this.ctx, lineChars[i], cursorLocation.lineIndex, i);
@ -401,6 +421,11 @@
lineLeft: lineLeftOffset
};
},
getMinWidth: function () {
return Math.max(this.minWidth, this.dynamicMinWidth);
},
/**
* Returns object representation of an instance
* @method toObject