mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-05-23 12:45:48 +00:00
Update to text, rendering and optimization
This commit is contained in:
parent
2fbebb03cc
commit
0e09961c64
11 changed files with 393 additions and 685 deletions
|
|
@ -241,14 +241,14 @@
|
|||
* @return {CanvasGradient}
|
||||
*/
|
||||
toLive: function(ctx, object) {
|
||||
var gradient, coords = fabric.util.object.clone(this.coords);
|
||||
var gradient, prop, coords = fabric.util.object.clone(this.coords);
|
||||
|
||||
if (!this.type) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (object.group && object.group.type === 'path-group') {
|
||||
for (var prop in coords) {
|
||||
for (prop in coords) {
|
||||
if (prop === 'x1' || prop === 'x2') {
|
||||
coords[prop] += -this.offsetX + object.width / 2;
|
||||
}
|
||||
|
|
@ -258,6 +258,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (object.type === 'text') {
|
||||
for (prop in coords) {
|
||||
if (prop === 'x1' || prop === 'x2') {
|
||||
coords[prop] -= object.width / 2;
|
||||
}
|
||||
else if (prop === 'y1' || prop === 'y2') {
|
||||
coords[prop] -= object.height / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.type === 'linear') {
|
||||
gradient = ctx.createLinearGradient(
|
||||
coords.x1, coords.y1, coords.x2, coords.y2);
|
||||
|
|
|
|||
|
|
@ -4,27 +4,26 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
_setSVGTextLineText: function(textLine, lineIndex, textSpans, lineHeight, lineTopOffsetMultiplier, textBgRects) {
|
||||
_setSVGTextLineText: function(lineIndex, textSpans, height, textLeftOffset, textTopOffset, textBgRects) {
|
||||
if (!this.styles[lineIndex]) {
|
||||
this.callSuper('_setSVGTextLineText',
|
||||
textLine, lineIndex, textSpans, lineHeight, lineTopOffsetMultiplier);
|
||||
lineIndex, textSpans, height, textLeftOffset, textTopOffset);
|
||||
}
|
||||
else {
|
||||
this._setSVGTextLineChars(
|
||||
textLine, lineIndex, textSpans, lineHeight, lineTopOffsetMultiplier, textBgRects);
|
||||
lineIndex, textSpans, height, textLeftOffset, textBgRects);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_setSVGTextLineChars: function(textLine, lineIndex, textSpans, lineHeight, lineTopOffsetMultiplier, textBgRects) {
|
||||
_setSVGTextLineChars: function(lineIndex, textSpans, height, textLeftOffset, textBgRects) {
|
||||
|
||||
var yProp = lineIndex === 0 || this.useNative ? 'y' : 'dy',
|
||||
chars = textLine.split(''),
|
||||
var chars = this._textLines[lineIndex].split(''),
|
||||
charOffset = 0,
|
||||
lineLeftOffset = this._getSVGLineLeftOffset(lineIndex),
|
||||
lineTopOffset = this._getSVGLineTopOffset(lineIndex),
|
||||
lineLeftOffset = this._getSVGLineLeftOffset(lineIndex) - this.width / 2,
|
||||
lineOffset = this._getSVGLineTopOffset(lineIndex),
|
||||
heightOfLine = this._getHeightOfLine(this.ctx, lineIndex);
|
||||
|
||||
for (var i = 0, len = chars.length; i < len; i++) {
|
||||
|
|
@ -32,14 +31,14 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
|
||||
textSpans.push(
|
||||
this._createTextCharSpan(
|
||||
chars[i], styleDecl, lineLeftOffset, lineTopOffset, yProp, charOffset));
|
||||
chars[i], styleDecl, lineLeftOffset, lineOffset.lineTop + lineOffset.offset, charOffset));
|
||||
|
||||
var charWidth = this._getWidthOfChar(this.ctx, chars[i], lineIndex, i);
|
||||
|
||||
if (styleDecl.textBackgroundColor) {
|
||||
textBgRects.push(
|
||||
this._createTextCharBg(
|
||||
styleDecl, lineLeftOffset, lineTopOffset, heightOfLine, charWidth, charOffset));
|
||||
styleDecl, lineLeftOffset, lineOffset.lineTop, heightOfLine, charWidth, charOffset));
|
||||
}
|
||||
|
||||
charOffset += charWidth;
|
||||
|
|
@ -50,20 +49,22 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
* @private
|
||||
*/
|
||||
_getSVGLineLeftOffset: function(lineIndex) {
|
||||
return (this._boundaries && this._boundaries[lineIndex])
|
||||
? fabric.util.toFixed(this._boundaries[lineIndex].left, 2)
|
||||
: 0;
|
||||
return fabric.util.toFixed(this._getLineLeftOffset(this.__lineWidths[lineIndex]), 2);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getSVGLineTopOffset: function(lineIndex) {
|
||||
var lineTopOffset = 0;
|
||||
for (var j = 0; j <= lineIndex; j++) {
|
||||
var lineTopOffset = 0, lastHeight = 0;
|
||||
for (var j = 0; j < lineIndex; j++) {
|
||||
lineTopOffset += this._getHeightOfLine(this.ctx, j);
|
||||
}
|
||||
return lineTopOffset - this.height / 2;
|
||||
lastHeight = this._getHeightOfLine(this.ctx, j);
|
||||
return {
|
||||
lineTop: lineTopOffset,
|
||||
offset: (this._fontSizeMult - this._fontSizeFraction) * lastHeight / (this.lineHeight * this._fontSizeMult)
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -73,13 +74,10 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
return [
|
||||
//jscs:disable validateIndentation
|
||||
'<rect fill="', styleDecl.textBackgroundColor,
|
||||
'" transform="translate(',
|
||||
-this.width / 2, ' ',
|
||||
-this.height + heightOfLine, ')',
|
||||
'" x="', lineLeftOffset + charOffset,
|
||||
'" y="', lineTopOffset + heightOfLine,
|
||||
'" y="', lineTopOffset - this.height/2,
|
||||
'" width="', charWidth,
|
||||
'" height="', heightOfLine,
|
||||
'" height="', heightOfLine / this.lineHeight,
|
||||
'"></rect>'
|
||||
//jscs:enable validateIndentation
|
||||
].join('');
|
||||
|
|
@ -88,7 +86,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
_createTextCharSpan: function(_char, styleDecl, lineLeftOffset, lineTopOffset, yProp, charOffset) {
|
||||
_createTextCharSpan: function(_char, styleDecl, lineLeftOffset, lineTopOffset, charOffset) {
|
||||
|
||||
var fillStyles = this.getSvgStyles.call(fabric.util.object.extend({
|
||||
visible: true,
|
||||
|
|
@ -99,16 +97,14 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
|
||||
return [
|
||||
//jscs:disable validateIndentation
|
||||
'<tspan x="', lineLeftOffset + charOffset, '" ',
|
||||
yProp, '="', lineTopOffset, '" ',
|
||||
|
||||
'<tspan x="', lineLeftOffset + charOffset, '" y="',
|
||||
lineTopOffset - this.height/2, '" ',
|
||||
(styleDecl.fontFamily ? 'font-family="' + styleDecl.fontFamily.replace(/"/g, '\'') + '" ': ''),
|
||||
(styleDecl.fontSize ? 'font-size="' + styleDecl.fontSize + '" ': ''),
|
||||
(styleDecl.fontStyle ? 'font-style="' + styleDecl.fontStyle + '" ': ''),
|
||||
(styleDecl.fontWeight ? 'font-weight="' + styleDecl.fontWeight + '" ': ''),
|
||||
(styleDecl.textDecoration ? 'text-decoration="' + styleDecl.textDecoration + '" ': ''),
|
||||
'style="', fillStyles, '">',
|
||||
|
||||
fabric.util.string.escapeXml(_char),
|
||||
'</tspan>'
|
||||
//jscs:enable validateIndentation
|
||||
|
|
|
|||
|
|
@ -157,10 +157,8 @@
|
|||
* Selects entire text
|
||||
*/
|
||||
selectAll: function() {
|
||||
this.selectionStart = 0;
|
||||
this.selectionEnd = this.text.length;
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
this.setSelectionStart(0);
|
||||
this.setSelectionEnd(this.text.length);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -375,6 +373,7 @@
|
|||
|
||||
this.hiddenTextarea.value = this.text;
|
||||
this.hiddenTextarea.selectionStart = this.selectionStart;
|
||||
this.hiddenTextarea.selectionEnd = this.selectionEnd;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -441,9 +440,8 @@
|
|||
* @private
|
||||
*/
|
||||
_removeExtraneousStyles: function() {
|
||||
var textLines = this.text.split(this._reNewline);
|
||||
for (var prop in this.styles) {
|
||||
if (!textLines[prop]) {
|
||||
if (!this._textLines[prop]) {
|
||||
delete this.styles[prop];
|
||||
}
|
||||
}
|
||||
|
|
@ -474,13 +472,14 @@
|
|||
|
||||
this.text = this.text.slice(0, start) +
|
||||
this.text.slice(end);
|
||||
this._clearCache();
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts a character where cursor is (replacing selection if one exists)
|
||||
* @param {String} _chars Characters to insert
|
||||
*/
|
||||
insertChars: function(_chars) {
|
||||
insertChars: function(_chars, useCopiedStyle) {
|
||||
var isEndOfLine = this.text.slice(this.selectionStart, this.selectionStart + 1) === '\n';
|
||||
|
||||
this.text = this.text.slice(0, this.selectionStart) +
|
||||
|
|
@ -488,21 +487,16 @@
|
|||
this.text.slice(this.selectionEnd);
|
||||
|
||||
if (this.selectionStart === this.selectionEnd) {
|
||||
this.insertStyleObjects(_chars, isEndOfLine, this.copiedStyles);
|
||||
this.insertStyleObjects(_chars, isEndOfLine, useCopiedStyle);
|
||||
}
|
||||
// else if (this.selectionEnd - this.selectionStart > 1) {
|
||||
// TODO: replace styles properly
|
||||
// console.log('replacing MORE than 1 char');
|
||||
// }
|
||||
|
||||
this.selectionStart += _chars.length;
|
||||
this.selectionEnd = this.selectionStart;
|
||||
|
||||
if (this.canvas) {
|
||||
// TODO: double renderAll gets rid of text box shift happenning sometimes
|
||||
// need to find out what exactly causes it and fix it
|
||||
this.canvas.renderAll().renderAll();
|
||||
}
|
||||
this.setSelectionStart(this.selectionStart + _chars.length);
|
||||
this.setSelectionEnd(this.selectionStart);
|
||||
this._clearCache();
|
||||
this.canvas && this.canvas.renderAll();
|
||||
|
||||
this.setCoords();
|
||||
this.fire('changed');
|
||||
|
|
@ -544,6 +538,7 @@
|
|||
}
|
||||
this.styles[lineIndex + 1] = newLineStyles;
|
||||
}
|
||||
this._clearCache();
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -573,15 +568,16 @@
|
|||
|
||||
this.styles[lineIndex][charIndex] =
|
||||
style || clone(currentLineStyles[charIndex - 1]);
|
||||
this._clearCache();
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts style object(s)
|
||||
* @param {String} _chars Characters at the location where style is inserted
|
||||
* @param {Boolean} isEndOfLine True if it's end of line
|
||||
* @param {Array} [styles] Styles to insert
|
||||
* @param {Boolean} [useCopiedStyle] Style to insert
|
||||
*/
|
||||
insertStyleObjects: function(_chars, isEndOfLine, styles) {
|
||||
insertStyleObjects: function(_chars, isEndOfLine, useCopiedStyle) {
|
||||
// removed shortcircuit over isEmptyStyles
|
||||
|
||||
var cursorLocation = this.get2DCursorLocation(),
|
||||
|
|
@ -596,8 +592,8 @@
|
|||
this.insertNewlineStyleObject(lineIndex, charIndex, isEndOfLine);
|
||||
}
|
||||
else {
|
||||
if (styles) {
|
||||
this._insertStyles(styles);
|
||||
if (useCopiedStyle) {
|
||||
this._insertStyles(this.copiedStyles);
|
||||
}
|
||||
else {
|
||||
// TODO: support multiple style insertion if _chars.length > 1
|
||||
|
|
@ -649,8 +645,7 @@
|
|||
|
||||
if (isBeginningOfLine) {
|
||||
|
||||
var textLines = this.text.split(this._reNewline),
|
||||
textOnPreviousLine = textLines[lineIndex - 1],
|
||||
var textOnPreviousLine = this._textLines[lineIndex - 1],
|
||||
newCharIndexOnPrevLine = textOnPreviousLine
|
||||
? textOnPreviousLine.length
|
||||
: 0;
|
||||
|
|
|
|||
|
|
@ -203,30 +203,30 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
*/
|
||||
getSelectionStartFromPointer: function(e) {
|
||||
var mouseOffset = this._getLocalRotatedPointer(e),
|
||||
textLines = this.text.split(this._reNewline),
|
||||
prevWidth = 0,
|
||||
width = 0,
|
||||
height = 0,
|
||||
charIndex = 0,
|
||||
newSelectionStart;
|
||||
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
newSelectionStart,
|
||||
line;
|
||||
|
||||
for (var i = 0, len = this._textLines.length; i < len; i++) {
|
||||
line = this._textLines[i].split('');
|
||||
height += this._getHeightOfLine(this.ctx, i) * this.scaleY;
|
||||
|
||||
var widthOfLine = this._getWidthOfLine(this.ctx, i, textLines),
|
||||
var widthOfLine = this._getLineWidth(this.ctx, i),
|
||||
lineLeftOffset = this._getLineLeftOffset(widthOfLine);
|
||||
|
||||
width = lineLeftOffset * this.scaleX;
|
||||
|
||||
if (this.flipX) {
|
||||
// when oject is horizontally flipped we reverse chars
|
||||
textLines[i] = textLines[i].split('').reverse().join('');
|
||||
this._textLines[i] = line.split('').reverse().join('');
|
||||
}
|
||||
|
||||
for (var j = 0, jlen = textLines[i].length; j < jlen; j++) {
|
||||
for (var j = 0, jlen = line.length; j < jlen; j++) {
|
||||
|
||||
var _char = textLines[i][j];
|
||||
var _char = line[j];
|
||||
prevWidth = width;
|
||||
|
||||
width += this._getWidthOfChar(this.ctx, _char, i, this.flipX ? jlen - j : j) *
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
if (!this.isEditing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.keyCode in this._keysMap) {
|
||||
this[this._keysMap[e.keyCode]](e);
|
||||
}
|
||||
|
|
@ -72,10 +71,8 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
e.stopImmediatePropagation();
|
||||
e.preventDefault();
|
||||
|
||||
this.canvas && this.canvas.renderAll();
|
||||
},
|
||||
|
||||
|
|
@ -125,7 +122,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
}
|
||||
|
||||
if (copiedText) {
|
||||
this.insertChars(copiedText);
|
||||
this.insertChars(copiedText, true);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -173,10 +170,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
*/
|
||||
getDownCursorOffset: function(e, isRight) {
|
||||
var selectionProp = isRight ? this.selectionEnd : this.selectionStart,
|
||||
textLines = this.text.split(this._reNewline),
|
||||
_char,
|
||||
lineLeftOffset,
|
||||
|
||||
_char, lineLeftOffset,
|
||||
textBeforeCursor = this.text.slice(0, selectionProp),
|
||||
textAfterCursor = this.text.slice(selectionProp),
|
||||
|
||||
|
|
@ -187,13 +181,13 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
cursorLocation = this.get2DCursorLocation(selectionProp);
|
||||
|
||||
// if on last line, down cursor goes to end of line
|
||||
if (cursorLocation.lineIndex === textLines.length - 1 || e.metaKey || e.keyCode === 34) {
|
||||
if (cursorLocation.lineIndex === this._textLines.length - 1 || e.metaKey || e.keyCode === 34) {
|
||||
|
||||
// move to the end of a text
|
||||
return this.text.length - selectionProp;
|
||||
}
|
||||
|
||||
var widthOfSameLineBeforeCursor = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex, textLines);
|
||||
var widthOfSameLineBeforeCursor = this._getLineWidth(this.ctx, cursorLocation.lineIndex);
|
||||
lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor);
|
||||
|
||||
var widthOfCharsOnSameLineBeforeCursor = lineLeftOffset,
|
||||
|
|
@ -205,7 +199,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
}
|
||||
|
||||
var indexOnNextLine = this._getIndexOnNextLine(
|
||||
cursorLocation, textOnNextLine, widthOfCharsOnSameLineBeforeCursor, textLines);
|
||||
cursorLocation, textOnNextLine, widthOfCharsOnSameLineBeforeCursor);
|
||||
|
||||
return textOnSameLineAfterCursor.length + 1 + indexOnNextLine;
|
||||
},
|
||||
|
|
@ -213,9 +207,9 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
_getIndexOnNextLine: function(cursorLocation, textOnNextLine, widthOfCharsOnSameLineBeforeCursor, textLines) {
|
||||
_getIndexOnNextLine: function(cursorLocation, textOnNextLine, widthOfCharsOnSameLineBeforeCursor) {
|
||||
var lineIndex = cursorLocation.lineIndex + 1,
|
||||
widthOfNextLine = this._getWidthOfLine(this.ctx, lineIndex, textLines),
|
||||
widthOfNextLine = this._getLineWidth(this.ctx, lineIndex),
|
||||
lineLeftOffset = this._getLineLeftOffset(widthOfNextLine),
|
||||
widthOfCharsOnNextLine = lineLeftOffset,
|
||||
indexOnNextLine = 0,
|
||||
|
|
@ -277,15 +271,8 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
*/
|
||||
moveCursorDownWithoutShift: function(offset) {
|
||||
this._selectionDirection = 'right';
|
||||
this.selectionStart += offset;
|
||||
|
||||
if (this.selectionStart > this.text.length) {
|
||||
this.selectionStart = this.text.length;
|
||||
}
|
||||
this.selectionEnd = this.selectionStart;
|
||||
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
this.setSelectionStart(this.selectionStart + offset);
|
||||
this.setSelectionEnd(this.selectionStart);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -293,8 +280,8 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
*/
|
||||
swapSelectionPoints: function() {
|
||||
var swapSel = this.selectionEnd;
|
||||
this.selectionEnd = this.selectionStart;
|
||||
this.selectionStart = swapSel;
|
||||
this.setSelectionEnd(this.selectionStart);
|
||||
this.setSelectionStart(swapSel);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -305,18 +292,19 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
if (this.selectionEnd === this.selectionStart) {
|
||||
this._selectionDirection = 'right';
|
||||
}
|
||||
var prop = this._selectionDirection === 'right' ? 'selectionEnd' : 'selectionStart';
|
||||
this[prop] += offset;
|
||||
if (this._selectionDirection === 'right') {
|
||||
this.setSelectionEnd(this.selectionEnd + offset);
|
||||
}
|
||||
else {
|
||||
this.setSelectionStart(this.selectionStart + offset);
|
||||
}
|
||||
if (this.selectionEnd < this.selectionStart && this._selectionDirection === 'left') {
|
||||
this.swapSelectionPoints();
|
||||
this._selectionDirection = 'right';
|
||||
}
|
||||
if (this.selectionEnd > this.text.length) {
|
||||
this.selectionEnd = this.text.length;
|
||||
this.setSelectionEnd(this.text.length);
|
||||
}
|
||||
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -335,9 +323,8 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
var textBeforeCursor = this.text.slice(0, selectionProp),
|
||||
textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\n') + 1),
|
||||
textOnPreviousLine = (textBeforeCursor.match(/\n?(.*)\n.*$/) || {})[1] || '',
|
||||
textLines = this.text.split(this._reNewline),
|
||||
_char,
|
||||
widthOfSameLineBeforeCursor = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex, textLines),
|
||||
widthOfSameLineBeforeCursor = this._getLineWidth(this.ctx, cursorLocation.lineIndex),
|
||||
lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor),
|
||||
widthOfCharsOnSameLineBeforeCursor = lineLeftOffset,
|
||||
lineIndex = cursorLocation.lineIndex;
|
||||
|
|
@ -348,7 +335,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
}
|
||||
|
||||
var indexOnPrevLine = this._getIndexOnPrevLine(
|
||||
cursorLocation, textOnPreviousLine, widthOfCharsOnSameLineBeforeCursor, textLines);
|
||||
cursorLocation, textOnPreviousLine, widthOfCharsOnSameLineBeforeCursor);
|
||||
|
||||
return textOnPreviousLine.length - indexOnPrevLine + textOnSameLineBeforeCursor.length;
|
||||
},
|
||||
|
|
@ -356,10 +343,10 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
_getIndexOnPrevLine: function(cursorLocation, textOnPreviousLine, widthOfCharsOnSameLineBeforeCursor, textLines) {
|
||||
_getIndexOnPrevLine: function(cursorLocation, textOnPreviousLine, widthOfCharsOnSameLineBeforeCursor) {
|
||||
|
||||
var lineIndex = cursorLocation.lineIndex - 1,
|
||||
widthOfPreviousLine = this._getWidthOfLine(this.ctx, lineIndex, textLines),
|
||||
widthOfPreviousLine = this._getLineWidth(this.ctx, lineIndex),
|
||||
lineLeftOffset = this._getLineLeftOffset(widthOfPreviousLine),
|
||||
widthOfCharsOnPreviousLine = lineLeftOffset,
|
||||
indexOnPrevLine = 0,
|
||||
|
|
@ -423,18 +410,16 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
if (this.selectionEnd === this.selectionStart) {
|
||||
this._selectionDirection = 'left';
|
||||
}
|
||||
var prop = this._selectionDirection === 'right' ? 'selectionEnd' : 'selectionStart';
|
||||
this[prop] -= offset;
|
||||
if (this._selectionDirection === 'right') {
|
||||
this.setSelectionEnd(this.selectionEnd - offset);
|
||||
}
|
||||
else {
|
||||
this.setSelectionStart(this.selectionStart - offset);
|
||||
}
|
||||
if (this.selectionEnd < this.selectionStart && this._selectionDirection === 'right') {
|
||||
this.swapSelectionPoints();
|
||||
this._selectionDirection = 'left';
|
||||
}
|
||||
if (this.selectionStart < 0) {
|
||||
this.selectionStart = 0;
|
||||
}
|
||||
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -443,17 +428,11 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
*/
|
||||
moveCursorUpWithoutShift: function(offset) {
|
||||
if (this.selectionStart === this.selectionEnd) {
|
||||
this.selectionStart -= offset;
|
||||
this.setSelectionStart(this.selectionStart - offset);
|
||||
}
|
||||
if (this.selectionStart < 0) {
|
||||
this.selectionStart = 0;
|
||||
}
|
||||
this.selectionEnd = this.selectionStart;
|
||||
this.setSelectionEnd(this.selectionStart);
|
||||
|
||||
this._selectionDirection = 'left';
|
||||
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -482,14 +461,15 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
* @private
|
||||
*/
|
||||
_move: function(e, prop, direction) {
|
||||
var propMethod = (prop === 'selectionStart' ? 'setSelectionStart' : 'setSelectionEnd');
|
||||
if (e.altKey) {
|
||||
this[prop] = this['findWordBoundary' + direction](this[prop]);
|
||||
this[propMethod](this['findWordBoundary' + direction](this[prop]));
|
||||
}
|
||||
else if (e.metaKey || e.keyCode === 35 || e.keyCode === 36 ) {
|
||||
this[prop] = this['findLineBoundary' + direction](this[prop]);
|
||||
this[propMethod](this['findLineBoundary' + direction](this[prop]));
|
||||
}
|
||||
else {
|
||||
this[prop] += (direction === 'Left' ? -1 : 1);
|
||||
this[propMethod](this[prop] + (direction === 'Left' ? -1 : 1));
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -519,10 +499,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
if (this.selectionEnd === this.selectionStart) {
|
||||
this._moveLeft(e, 'selectionStart');
|
||||
}
|
||||
this.selectionEnd = this.selectionStart;
|
||||
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
this.setSelectionEnd(this.selectionStart);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -539,15 +516,9 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
|
||||
// increase selection by one if it's a newline
|
||||
if (this.text.charAt(this.selectionStart) === '\n') {
|
||||
this.selectionStart--;
|
||||
}
|
||||
if (this.selectionStart < 0) {
|
||||
this.selectionStart = 0;
|
||||
this.setSelectionStart(this.selectionStart - 1);
|
||||
}
|
||||
}
|
||||
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -586,15 +557,9 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
|
||||
// increase selection by one if it's a newline
|
||||
if (this.text.charAt(this.selectionEnd - 1) === '\n') {
|
||||
this.selectionEnd++;
|
||||
}
|
||||
if (this.selectionEnd > this.text.length) {
|
||||
this.selectionEnd = this.text.length;
|
||||
this.setSelectionEnd(this.selectionEnd + 1);
|
||||
}
|
||||
}
|
||||
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -606,22 +571,16 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
|
||||
if (this.selectionStart === this.selectionEnd) {
|
||||
this._moveRight(e, 'selectionStart');
|
||||
this.selectionEnd = this.selectionStart;
|
||||
this.setSelectionEnd(this.selectionStart);
|
||||
}
|
||||
else {
|
||||
this.selectionEnd += this.getNumNewLinesInSelectedText();
|
||||
if (this.selectionEnd > this.text.length) {
|
||||
this.selectionEnd = this.text.length;
|
||||
}
|
||||
this.selectionStart = this.selectionEnd;
|
||||
this.setSelectionEnd(this.selectionEnd + this.getNumNewLinesInSelectedText());
|
||||
this.setSelectionStart(this.selectionEnd);
|
||||
}
|
||||
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts a character where cursor is (replacing selection if one exists)
|
||||
* Removes characters selected by selection
|
||||
* @param {Event} e Event object
|
||||
*/
|
||||
removeChars: function(e) {
|
||||
|
|
@ -632,15 +591,12 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
this._removeCharsFromTo(this.selectionStart, this.selectionEnd);
|
||||
}
|
||||
|
||||
this.selectionEnd = this.selectionStart;
|
||||
this.setSelectionEnd(this.selectionStart);
|
||||
|
||||
this._removeExtraneousStyles();
|
||||
|
||||
if (this.canvas) {
|
||||
// TODO: double renderAll gets rid of text box shift happenning sometimes
|
||||
// need to find out what exactly causes it and fix it
|
||||
this.canvas.renderAll().renderAll();
|
||||
}
|
||||
this._clearCache();
|
||||
this.canvas && this.canvas.renderAll();
|
||||
|
||||
this.setCoords();
|
||||
this.fire('changed');
|
||||
|
|
@ -659,20 +615,19 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
var leftLineBoundary = this.findLineBoundaryLeft(this.selectionStart);
|
||||
|
||||
this._removeCharsFromTo(leftLineBoundary, this.selectionStart);
|
||||
this.selectionStart = leftLineBoundary;
|
||||
this.setSelectionStart(leftLineBoundary);
|
||||
}
|
||||
else if (e.altKey) {
|
||||
// remove all till the start of current word
|
||||
var leftWordBoundary = this.findWordBoundaryLeft(this.selectionStart);
|
||||
|
||||
this._removeCharsFromTo(leftWordBoundary, this.selectionStart);
|
||||
this.selectionStart = leftWordBoundary;
|
||||
this.setSelectionStart(leftWordBoundary);
|
||||
}
|
||||
else {
|
||||
var isBeginningOfLine = this.text.slice(this.selectionStart - 1, this.selectionStart) === '\n';
|
||||
this.removeStyleObject(isBeginningOfLine);
|
||||
|
||||
this.selectionStart--;
|
||||
this.setSelectionStart(this.selectionStart - 1);
|
||||
this.text = this.text.slice(0, this.selectionStart) +
|
||||
this.text.slice(this.selectionStart + 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|||
opacity = typeof this.opacity !== 'undefined' ? this.opacity : '1',
|
||||
|
||||
visibility = this.visible ? '' : ' visibility: hidden;',
|
||||
filter = this.shadow && this.type !== 'text' ? 'filter: url(#SVGID_' + this.shadow.id + ');' : '';
|
||||
filter = this.shadow ? 'filter: url(#SVGID_' + this.shadow.id + ');' : '';
|
||||
|
||||
return [
|
||||
'stroke: ', stroke, '; ',
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@
|
|||
* Select text vertically: shift + up, shift + down
|
||||
* Move cursor by word: alt + left, alt + right
|
||||
* Select words: shift + alt + left, shift + alt + right
|
||||
* Move cursor to line start/end: cmd + left, cmd + right
|
||||
* Select till start/end of line: cmd + shift + left, cmd + shift + right
|
||||
* Move cursor to line start/end: cmd + left, cmd + right or home, end
|
||||
* Select till start/end of line: cmd + shift + left, cmd + shift + right or shift + home, shift + end
|
||||
* Jump to start/end of text: cmd + up, cmd + down
|
||||
* Select till start/end of text: cmd + shift + up, cmd + shift + down
|
||||
* Select till start/end of text: cmd + shift + up, cmd + shift + down or shift + pgUp, shift + pgDown
|
||||
* Delete character: backspace
|
||||
* Delete word: alt + backspace
|
||||
* Delete line: cmd + backspace
|
||||
|
|
@ -36,6 +36,7 @@
|
|||
* Paste text: ctrl/cmd + v
|
||||
* Cut text: ctrl/cmd + x
|
||||
* Select entire text: ctrl/cmd + a
|
||||
* Quit editing tab or esc
|
||||
* </pre>
|
||||
*
|
||||
* <p>Supported mouse/touch combination</p>
|
||||
|
|
@ -146,18 +147,13 @@
|
|||
* @type Boolean
|
||||
* @default
|
||||
*/
|
||||
_skipFillStrokeCheck: true,
|
||||
_skipFillStrokeCheck: false,
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_reSpace: /\s|\n/,
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_fontSizeFraction: 4,
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
|
@ -191,10 +187,14 @@
|
|||
|
||||
fabric.IText.instances.push(this);
|
||||
|
||||
// caching
|
||||
this.__lineWidths = { };
|
||||
this.__lineHeights = { };
|
||||
this.__lineOffsets = { };
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_clearCache: function() {
|
||||
this.callSuper('_clearCache');
|
||||
this.__maxFontHeights = [ ];
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -222,12 +222,13 @@
|
|||
* @param {Number} index Index to set selection start to
|
||||
*/
|
||||
setSelectionStart: function(index) {
|
||||
index = Math.max(index, 0);
|
||||
if (this.selectionStart !== index) {
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
this.selectionStart = index;
|
||||
}
|
||||
this.selectionStart = index;
|
||||
this.hiddenTextarea && (this.hiddenTextarea.selectionStart = index);
|
||||
this._updateTextarea();
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -235,12 +236,13 @@
|
|||
* @param {Number} index Index to set selection end to
|
||||
*/
|
||||
setSelectionEnd: function(index) {
|
||||
index = Math.min(index, this.text.length);
|
||||
if (this.selectionEnd !== index) {
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
this.selectionEnd = index;
|
||||
}
|
||||
this.selectionEnd = index;
|
||||
this.hiddenTextarea && (this.hiddenTextarea.selectionEnd = index);
|
||||
this._updateTextarea();
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -405,18 +407,14 @@
|
|||
*/
|
||||
_getCursorBoundaries: function(chars, typeOfBoundaries) {
|
||||
|
||||
var cursorLocation = this.get2DCursorLocation(),
|
||||
|
||||
textLines = this.text.split(this._reNewline),
|
||||
|
||||
// left/top are left/top of entire text box
|
||||
// leftOffset/topOffset are offset from that left/top point of a text box
|
||||
|
||||
left = Math.round(this._getLeftOffset()),
|
||||
var left = Math.round(this._getLeftOffset()),
|
||||
top = this._getTopOffset(),
|
||||
|
||||
offsets = this._getCursorBoundariesOffsets(
|
||||
chars, typeOfBoundaries, cursorLocation, textLines);
|
||||
chars, typeOfBoundaries);
|
||||
|
||||
return {
|
||||
left: left,
|
||||
|
|
@ -429,26 +427,19 @@
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
_getCursorBoundariesOffsets: function(chars, typeOfBoundaries, cursorLocation, textLines) {
|
||||
_getCursorBoundariesOffsets: function(chars, typeOfBoundaries) {
|
||||
|
||||
var lineLeftOffset = 0,
|
||||
|
||||
lineIndex = 0,
|
||||
charIndex = 0,
|
||||
|
||||
leftOffset = 0,
|
||||
topOffset = typeOfBoundaries === 'cursor'
|
||||
// selection starts at the very top of the line,
|
||||
// whereas cursor starts at the padding created by line height
|
||||
? (this._getHeightOfLine(this.ctx, 0) -
|
||||
this.getCurrentCharFontSize(cursorLocation.lineIndex, cursorLocation.charIndex))
|
||||
: 0;
|
||||
topOffset = 0,
|
||||
leftOffset = 0;
|
||||
|
||||
for (var i = 0; i < this.selectionStart; i++) {
|
||||
if (chars[i] === '\n') {
|
||||
leftOffset = 0;
|
||||
var index = lineIndex + (typeOfBoundaries === 'cursor' ? 1 : 0);
|
||||
topOffset += this._getCachedLineHeight(index);
|
||||
topOffset += this._getHeightOfLine(this.ctx, lineIndex);
|
||||
|
||||
lineIndex++;
|
||||
charIndex = 0;
|
||||
|
|
@ -458,10 +449,12 @@
|
|||
charIndex++;
|
||||
}
|
||||
|
||||
lineLeftOffset = this._getCachedLineOffset(lineIndex, textLines);
|
||||
lineLeftOffset = this._getCachedLineOffset(lineIndex);
|
||||
}
|
||||
if (typeOfBoundaries === 'cursor') {
|
||||
topOffset += (1 - this._fontSizeFraction) * this._getHeightOfLine(this.ctx, lineIndex) / this.lineHeight
|
||||
- this.getCurrentCharFontSize(lineIndex, charIndex) * (1 - this._fontSizeFraction);
|
||||
}
|
||||
|
||||
this._clearCache();
|
||||
|
||||
return {
|
||||
top: topOffset,
|
||||
|
|
@ -473,33 +466,8 @@
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
_clearCache: function() {
|
||||
this.__lineWidths = { };
|
||||
this.__lineHeights = { };
|
||||
this.__lineOffsets = { };
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getCachedLineHeight: function(index) {
|
||||
return this.__lineHeights[index] ||
|
||||
(this.__lineHeights[index] = this._getHeightOfLine(this.ctx, index));
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getCachedLineWidth: function(lineIndex, textLines) {
|
||||
return this.__lineWidths[lineIndex] ||
|
||||
(this.__lineWidths[lineIndex] = this._getWidthOfLine(this.ctx, lineIndex, textLines));
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getCachedLineOffset: function(lineIndex, textLines) {
|
||||
var widthOfLine = this._getCachedLineWidth(lineIndex, textLines);
|
||||
_getCachedLineOffset: function(lineIndex) {
|
||||
var widthOfLine = this._getLineWidth(this.ctx, lineIndex);
|
||||
|
||||
return this.__lineOffsets[lineIndex] ||
|
||||
(this.__lineOffsets[lineIndex] = this._getLineLeftOffset(widthOfLine));
|
||||
|
|
@ -549,30 +517,29 @@
|
|||
var start = this.get2DCursorLocation(this.selectionStart),
|
||||
end = this.get2DCursorLocation(this.selectionEnd),
|
||||
startLine = start.lineIndex,
|
||||
endLine = end.lineIndex,
|
||||
textLines = this.text.split(this._reNewline);
|
||||
endLine = end.lineIndex;
|
||||
|
||||
for (var i = startLine; i <= endLine; i++) {
|
||||
var lineOffset = this._getCachedLineOffset(i, textLines) || 0,
|
||||
lineHeight = this._getCachedLineHeight(i),
|
||||
boxWidth = 0;
|
||||
var lineOffset = this._getCachedLineOffset(i) || 0,
|
||||
lineHeight = this._getHeightOfLine(this.ctx, i),
|
||||
boxWidth = 0, line = this._textLines[i];
|
||||
|
||||
if (i === startLine) {
|
||||
for (var j = 0, len = textLines[i].length; j < len; j++) {
|
||||
for (var j = 0, len = line.length; j < len; j++) {
|
||||
if (j >= start.charIndex && (i !== endLine || j < end.charIndex)) {
|
||||
boxWidth += this._getWidthOfChar(ctx, textLines[i][j], i, j);
|
||||
boxWidth += this._getWidthOfChar(ctx, line[j], i, j);
|
||||
}
|
||||
if (j < start.charIndex) {
|
||||
lineOffset += this._getWidthOfChar(ctx, textLines[i][j], i, j);
|
||||
lineOffset += this._getWidthOfChar(ctx, line[j], i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (i > startLine && i < endLine) {
|
||||
boxWidth += this._getCachedLineWidth(i, textLines) || 5;
|
||||
boxWidth += this._getLineWidth(ctx, i) || 5;
|
||||
}
|
||||
else if (i === endLine) {
|
||||
for (var j2 = 0, j2len = end.charIndex; j2 < j2len; j2++) {
|
||||
boxWidth += this._getWidthOfChar(ctx, textLines[i][j2], i, j2);
|
||||
boxWidth += this._getWidthOfChar(ctx, line[j2], i, j2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -608,10 +575,8 @@
|
|||
: 0;
|
||||
|
||||
// set proper line offset
|
||||
var textLines = this.text.split(this._reNewline),
|
||||
lineWidth = this._getWidthOfLine(ctx, lineIndex, textLines),
|
||||
lineHeight = this._getHeightOfLine(ctx, lineIndex, textLines),
|
||||
lineLeftOffset = this._getLineLeftOffset(lineWidth),
|
||||
var lineHeight = this._getHeightOfLine(ctx, lineIndex),
|
||||
lineLeftOffset = this._getCachedLineOffset(lineIndex),
|
||||
chars = line.split(''),
|
||||
prevStyle,
|
||||
charsToRender = '';
|
||||
|
|
@ -619,7 +584,7 @@
|
|||
left += lineLeftOffset || 0;
|
||||
|
||||
ctx.save();
|
||||
|
||||
top -= lineHeight / this.lineHeight * this._fontSizeFraction;
|
||||
for (var i = 0, len = chars.length; i <= len; i++) {
|
||||
prevStyle = prevStyle || this.getCurrentCharStyle(lineIndex, i);
|
||||
var thisStyle = this.getCurrentCharStyle(lineIndex, i + 1);
|
||||
|
|
@ -649,7 +614,7 @@
|
|||
if (method === 'fillText' && this.fill) {
|
||||
this.callSuper('_renderChars', method, ctx, line, left, top);
|
||||
}
|
||||
if (method === 'strokeText' && this.stroke) {
|
||||
if (method === 'strokeText' && ((this.stroke && this.strokeWidth > 0) || this.skipFillStrokeCheck)) {
|
||||
this.callSuper('_renderChars', method, ctx, line, left, top);
|
||||
}
|
||||
},
|
||||
|
|
@ -666,7 +631,8 @@
|
|||
* @param {Number} lineHeight Height of the line
|
||||
*/
|
||||
_renderChar: function(method, ctx, lineIndex, i, _char, left, top, lineHeight) {
|
||||
var decl, charWidth, charHeight;
|
||||
var decl, charWidth, charHeight,
|
||||
offset = this._fontSizeFraction * lineHeight / this.lineHeight;
|
||||
|
||||
if (this.styles && this.styles[lineIndex] && (decl = this.styles[lineIndex][i])) {
|
||||
|
||||
|
|
@ -684,7 +650,7 @@
|
|||
ctx.strokeText(_char, left, top);
|
||||
}
|
||||
|
||||
this._renderCharDecoration(ctx, decl, left, top, charWidth, lineHeight, charHeight);
|
||||
this._renderCharDecoration(ctx, decl, left, top, offset, charWidth, charHeight);
|
||||
ctx.restore();
|
||||
|
||||
ctx.translate(charWidth, 0);
|
||||
|
|
@ -697,7 +663,7 @@
|
|||
ctx[method](_char, left, top);
|
||||
}
|
||||
charWidth = this._applyCharStylesGetWidth(ctx, _char, lineIndex, i);
|
||||
this._renderCharDecoration(ctx, null, left, top, charWidth, lineHeight);
|
||||
this._renderCharDecoration(ctx, null, left, top, offset, charWidth, this.fontSize);
|
||||
|
||||
ctx.translate(ctx.measureText(_char).width, 0);
|
||||
}
|
||||
|
|
@ -725,58 +691,42 @@
|
|||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_renderCharDecoration: function(ctx, styleDeclaration, left, top, charWidth, lineHeight, charHeight) {
|
||||
_renderCharDecoration: function(ctx, styleDeclaration, left, top, offset, charWidth, charHeight) {
|
||||
|
||||
var textDecoration = styleDeclaration
|
||||
? (styleDeclaration.textDecoration || this.textDecoration)
|
||||
: this.textDecoration,
|
||||
|
||||
fontSize = (styleDeclaration ? styleDeclaration.fontSize : null) || this.fontSize;
|
||||
: this.textDecoration;
|
||||
|
||||
if (!textDecoration) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (textDecoration.indexOf('underline') > -1) {
|
||||
this._renderCharDecorationAtOffset(
|
||||
ctx,
|
||||
ctx.fillRect(
|
||||
left,
|
||||
top + (this.fontSize / this._fontSizeFraction),
|
||||
charWidth,
|
||||
0,
|
||||
this.fontSize / 20
|
||||
top + charHeight / 10,
|
||||
charWidth ,
|
||||
charHeight / 15
|
||||
);
|
||||
}
|
||||
if (textDecoration.indexOf('line-through') > -1) {
|
||||
this._renderCharDecorationAtOffset(
|
||||
ctx,
|
||||
ctx.fillRect(
|
||||
left,
|
||||
top + (this.fontSize / this._fontSizeFraction),
|
||||
top - charHeight * (this._fontSizeFraction + this._fontSizeMult - 1) + charHeight / 15,
|
||||
charWidth,
|
||||
charHeight / 2,
|
||||
fontSize / 20
|
||||
charHeight / 15
|
||||
);
|
||||
}
|
||||
if (textDecoration.indexOf('overline') > -1) {
|
||||
this._renderCharDecorationAtOffset(
|
||||
ctx,
|
||||
ctx.fillRect(
|
||||
left,
|
||||
top,
|
||||
top - (this._fontSizeMult - this._fontSizeFraction) * charHeight,
|
||||
charWidth,
|
||||
lineHeight - (this.fontSize / this._fontSizeFraction),
|
||||
this.fontSize / 20
|
||||
charHeight / 15
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_renderCharDecorationAtOffset: function(ctx, left, top, charWidth, offset, thickness) {
|
||||
ctx.fillRect(left, top - offset, charWidth, thickness);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {String} method
|
||||
|
|
@ -785,27 +735,26 @@
|
|||
*/
|
||||
_renderTextLine: function(method, ctx, line, left, top, lineIndex) {
|
||||
// to "cancel" this.fontSize subtraction in fabric.Text#_renderTextLine
|
||||
top += this.fontSize / 4;
|
||||
// the adding 0.03 is just to align text with itext by overlap test
|
||||
top += this.fontSize * (this._fontSizeFraction + 0.03);
|
||||
this.callSuper('_renderTextLine', method, ctx, line, left, top, lineIndex);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines
|
||||
*/
|
||||
_renderTextDecoration: function(ctx, textLines) {
|
||||
_renderTextDecoration: function(ctx) {
|
||||
if (this.isEmptyStyles()) {
|
||||
return this.callSuper('_renderTextDecoration', ctx, textLines);
|
||||
return this.callSuper('_renderTextDecoration', ctx);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextLinesBackground: function(ctx, textLines) {
|
||||
_renderTextLinesBackground: function(ctx) {
|
||||
if (!this.textBackgroundColor && !this.styles) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -816,43 +765,42 @@
|
|||
ctx.fillStyle = this.textBackgroundColor;
|
||||
}
|
||||
|
||||
var lineHeights = 0,
|
||||
fractionOfFontSize = this.fontSize / this._fontSizeFraction;
|
||||
var lineHeights = 0;
|
||||
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
for (var i = 0, len = this._textLines.length; i < len; i++) {
|
||||
|
||||
var heightOfLine = this._getHeightOfLine(ctx, i, textLines);
|
||||
if (textLines[i] === '') {
|
||||
var heightOfLine = this._getHeightOfLine(ctx, i);
|
||||
if (this._textLines[i] === '') {
|
||||
lineHeights += heightOfLine;
|
||||
continue;
|
||||
}
|
||||
|
||||
var lineWidth = this._getWidthOfLine(ctx, i, textLines),
|
||||
lineLeftOffset = this._getLineLeftOffset(lineWidth);
|
||||
var lineWidth = this._getLineWidth(ctx, i),
|
||||
lineLeftOffset = this._getCachedLineOffset(i);
|
||||
|
||||
if (this.textBackgroundColor) {
|
||||
ctx.fillStyle = this.textBackgroundColor;
|
||||
|
||||
ctx.fillRect(
|
||||
this._getLeftOffset() + lineLeftOffset,
|
||||
this._getTopOffset() + lineHeights + fractionOfFontSize,
|
||||
this._getTopOffset() + lineHeights,
|
||||
lineWidth,
|
||||
heightOfLine
|
||||
heightOfLine / this.lineHeight
|
||||
);
|
||||
}
|
||||
if (this.styles[i]) {
|
||||
for (var j = 0, jlen = textLines[i].length; j < jlen; j++) {
|
||||
for (var j = 0, jlen = this._textLines[i].length; j < jlen; j++) {
|
||||
if (this.styles[i] && this.styles[i][j] && this.styles[i][j].textBackgroundColor) {
|
||||
|
||||
var _char = textLines[i][j];
|
||||
var _char = this._textLines[i][j];
|
||||
|
||||
ctx.fillStyle = this.styles[i][j].textBackgroundColor;
|
||||
|
||||
ctx.fillRect(
|
||||
this._getLeftOffset() + lineLeftOffset + this._getWidthOfCharsAt(ctx, i, j, textLines),
|
||||
this._getTopOffset() + lineHeights + fractionOfFontSize,
|
||||
this._getWidthOfChar(ctx, _char, i, j, textLines) + 1,
|
||||
heightOfLine
|
||||
this._getLeftOffset() + lineLeftOffset + this._getWidthOfCharsAt(ctx, i, j),
|
||||
this._getTopOffset() + lineHeights,
|
||||
this._getWidthOfChar(ctx, _char, i, j) + 1,
|
||||
heightOfLine / this.lineHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -867,12 +815,10 @@
|
|||
*/
|
||||
_getCacheProp: function(_char, styleDeclaration) {
|
||||
return _char +
|
||||
|
||||
styleDeclaration.fontFamily +
|
||||
styleDeclaration.fontSize +
|
||||
styleDeclaration.fontWeight +
|
||||
styleDeclaration.fontStyle +
|
||||
|
||||
styleDeclaration.shadow;
|
||||
},
|
||||
|
||||
|
|
@ -1005,9 +951,8 @@
|
|||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_getWidthOfCharAt: function(ctx, lineIndex, charIndex, lines) {
|
||||
lines = lines || this.text.split(this._reNewline);
|
||||
var _char = lines[lineIndex].split('')[charIndex];
|
||||
_getWidthOfCharAt: function(ctx, lineIndex, charIndex) {
|
||||
var _char = this._textLines[lineIndex].split('')[charIndex];
|
||||
return this._getWidthOfChar(ctx, _char, lineIndex, charIndex);
|
||||
},
|
||||
|
||||
|
|
@ -1015,9 +960,8 @@
|
|||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_getHeightOfCharAt: function(ctx, lineIndex, charIndex, lines) {
|
||||
lines = lines || this.text.split(this._reNewline);
|
||||
var _char = lines[lineIndex].split('')[charIndex];
|
||||
_getHeightOfCharAt: function(ctx, lineIndex, charIndex) {
|
||||
var _char = this._textLines[lineIndex].split('')[charIndex];
|
||||
return this._getHeightOfChar(ctx, _char, lineIndex, charIndex);
|
||||
},
|
||||
|
||||
|
|
@ -1025,10 +969,10 @@
|
|||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_getWidthOfCharsAt: function(ctx, lineIndex, charIndex, lines) {
|
||||
_getWidthOfCharsAt: function(ctx, lineIndex, charIndex) {
|
||||
var width = 0;
|
||||
for (var i = 0; i < charIndex; i++) {
|
||||
width += this._getWidthOfCharAt(ctx, lineIndex, i, lines);
|
||||
width += this._getWidthOfCharAt(ctx, lineIndex, i);
|
||||
}
|
||||
return width;
|
||||
},
|
||||
|
|
@ -1037,11 +981,12 @@
|
|||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_getWidthOfLine: function(ctx, lineIndex, textLines) {
|
||||
// if (!this.styles[lineIndex]) {
|
||||
// return this.callSuper('_getLineWidth', ctx, textLines[lineIndex]);
|
||||
// }
|
||||
return this._getWidthOfCharsAt(ctx, lineIndex, textLines[lineIndex].length, textLines);
|
||||
_getLineWidth: function(ctx, lineIndex) {
|
||||
if (this.__lineWidths[lineIndex]) {
|
||||
return this.__lineWidths[lineIndex];
|
||||
}
|
||||
this.__lineWidths[lineIndex] = this._getWidthOfCharsAt(ctx, lineIndex, this._textLines[lineIndex].length);
|
||||
return this.__lineWidths[lineIndex];
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -1085,33 +1030,13 @@
|
|||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_getTextWidth: function(ctx, textLines) {
|
||||
|
||||
if (this.isEmptyStyles()) {
|
||||
return this.callSuper('_getTextWidth', ctx, textLines);
|
||||
_getHeightOfLine: function(ctx, lineIndex) {
|
||||
if (this.__lineHeights[lineIndex]) {
|
||||
return this.__lineHeights[lineIndex];
|
||||
}
|
||||
|
||||
var maxWidth = this._getWidthOfLine(ctx, 0, textLines);
|
||||
|
||||
for (var i = 1, len = textLines.length; i < len; i++) {
|
||||
var currentLineWidth = this._getWidthOfLine(ctx, i, textLines);
|
||||
if (currentLineWidth > maxWidth) {
|
||||
maxWidth = currentLineWidth;
|
||||
}
|
||||
}
|
||||
return maxWidth;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_getHeightOfLine: function(ctx, lineIndex, textLines) {
|
||||
|
||||
textLines = textLines || this.text.split(this._reNewline);
|
||||
|
||||
var maxHeight = this._getHeightOfChar(ctx, textLines[lineIndex][0], lineIndex, 0),
|
||||
line = textLines[lineIndex],
|
||||
var line = this._textLines[lineIndex],
|
||||
maxHeight = this._getHeightOfChar(ctx, line[0], lineIndex, 0),
|
||||
chars = line.split('');
|
||||
|
||||
for (var i = 1, len = chars.length; i < len; i++) {
|
||||
|
|
@ -1120,31 +1045,23 @@
|
|||
maxHeight = currentCharHeight;
|
||||
}
|
||||
}
|
||||
|
||||
return maxHeight * this.lineHeight;
|
||||
this.__maxFontHeights[lineIndex] = maxHeight;
|
||||
this.__lineHeights[lineIndex] = maxHeight * this.lineHeight * this._fontSizeMult;
|
||||
return this.__lineHeights[lineIndex];
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_getTextHeight: function(ctx, textLines) {
|
||||
_getTextHeight: function(ctx) {
|
||||
var height = 0;
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
height += this._getHeightOfLine(ctx, i, textLines);
|
||||
for (var i = 0, len = this._textLines.length; i < len; i++) {
|
||||
height += this._getHeightOfLine(ctx, i);
|
||||
}
|
||||
return height;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getTopOffset: function() {
|
||||
var topOffset = fabric.Text.prototype._getTopOffset.call(this);
|
||||
return topOffset - (this.fontSize / this._fontSizeFraction);
|
||||
},
|
||||
|
||||
/**
|
||||
* This method is overwritten to account for different top offset
|
||||
* @private
|
||||
|
|
@ -1159,7 +1076,7 @@
|
|||
|
||||
ctx.fillRect(
|
||||
this._getLeftOffset(),
|
||||
this._getTopOffset() + (this.fontSize / this._fontSizeFraction),
|
||||
this._getTopOffset(),
|
||||
this.width,
|
||||
this.height
|
||||
);
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@
|
|||
'textAlign',
|
||||
'fontStyle',
|
||||
'lineHeight',
|
||||
'textBackgroundColor',
|
||||
'useNative',
|
||||
'path'
|
||||
'textBackgroundColor'
|
||||
);
|
||||
|
||||
/**
|
||||
|
|
@ -258,7 +256,7 @@
|
|||
* @type Number
|
||||
* @default
|
||||
*/
|
||||
lineHeight: 1.3,
|
||||
lineHeight: 1.16,
|
||||
|
||||
/**
|
||||
* Background color of text lines
|
||||
|
|
@ -267,20 +265,6 @@
|
|||
*/
|
||||
textBackgroundColor: '',
|
||||
|
||||
/**
|
||||
* URL of a font file, when using Cufon
|
||||
* @type String | null
|
||||
* @default
|
||||
*/
|
||||
path: null,
|
||||
|
||||
/**
|
||||
* Indicates whether canvas native text methods should be used to render text (otherwise, Cufon is used)
|
||||
* @type Boolean
|
||||
* @default
|
||||
*/
|
||||
useNative: true,
|
||||
|
||||
/**
|
||||
* List of properties to consider when checking if
|
||||
* state of an object is changed ({@link fabric.Object#hasStateChanged})
|
||||
|
|
@ -305,6 +289,18 @@
|
|||
*/
|
||||
shadow: null,
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_fontSizeFraction: 0.25,
|
||||
|
||||
/**
|
||||
* Text Line proportion to font Size (in pixels)
|
||||
* @type Number
|
||||
* @default
|
||||
*/
|
||||
_fontSizeMult: 1.13,
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param {String} text Text string
|
||||
|
|
@ -313,7 +309,6 @@
|
|||
*/
|
||||
initialize: function(text, options) {
|
||||
options = options || { };
|
||||
|
||||
this.text = text;
|
||||
this.__skipDimension = true;
|
||||
this.setOptions(options);
|
||||
|
|
@ -329,8 +324,13 @@
|
|||
if (this.__skipDimension) {
|
||||
return;
|
||||
}
|
||||
var canvasEl = fabric.util.createCanvasElement();
|
||||
this._render(canvasEl.getContext('2d'));
|
||||
this._clearCache();
|
||||
|
||||
var ctx = fabric.util.createCanvasElement().getContext('2d');
|
||||
this._textLines = this.text.split(this._reNewline);
|
||||
this._setTextStyles(ctx);
|
||||
this.width = this._getTextWidth(ctx);
|
||||
this.height = this._getTextHeight(ctx);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -348,54 +348,31 @@
|
|||
*/
|
||||
_render: function(ctx) {
|
||||
|
||||
if (typeof Cufon === 'undefined' || this.useNative === true) {
|
||||
this._renderViaNative(ctx);
|
||||
}
|
||||
else {
|
||||
this._renderViaCufon(ctx);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_renderViaNative: function(ctx) {
|
||||
var textLines = this.text.split(this._reNewline);
|
||||
|
||||
this._setTextStyles(ctx);
|
||||
|
||||
this.width = this._getTextWidth(ctx, textLines);
|
||||
this.height = this._getTextHeight(ctx, textLines);
|
||||
|
||||
this.clipTo && fabric.util.clipContext(this, ctx);
|
||||
|
||||
this._renderTextBackground(ctx, textLines);
|
||||
this._renderTextBackground(ctx);
|
||||
this._translateForTextAlign(ctx);
|
||||
this._renderText(ctx, textLines);
|
||||
this._renderText(ctx);
|
||||
|
||||
if (this.textAlign !== 'left' && this.textAlign !== 'justify') {
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
this._renderTextDecoration(ctx, textLines);
|
||||
this._renderTextDecoration(ctx);
|
||||
this.clipTo && ctx.restore();
|
||||
|
||||
this._setBoundaries(ctx, textLines);
|
||||
this._totalLineHeight = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_renderText: function(ctx, textLines) {
|
||||
_renderText: function(ctx) {
|
||||
ctx.save();
|
||||
this._setOpacity(ctx);
|
||||
this._setShadow(ctx);
|
||||
this._setupCompositeOperation(ctx);
|
||||
this._renderTextFill(ctx, textLines);
|
||||
this._renderTextStroke(ctx, textLines);
|
||||
this._renderTextFill(ctx);
|
||||
this._renderTextStroke(ctx);
|
||||
this._restoreCompositeOperation(ctx);
|
||||
this._removeShadow(ctx);
|
||||
ctx.restore();
|
||||
|
|
@ -412,34 +389,11 @@
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_setBoundaries: function(ctx, textLines) {
|
||||
this._boundaries = [ ];
|
||||
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
|
||||
var lineWidth = this._getLineWidth(ctx, textLines[i]),
|
||||
lineLeftOffset = this._getLineLeftOffset(lineWidth);
|
||||
|
||||
this._boundaries.push({
|
||||
height: this.fontSize * this.lineHeight,
|
||||
width: lineWidth,
|
||||
left: lineLeftOffset
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_setTextStyles: function(ctx) {
|
||||
this._setFillStyles(ctx);
|
||||
this._setStrokeStyles(ctx);
|
||||
ctx.textBaseline = 'alphabetic';
|
||||
if (!this.skipTextAlign) {
|
||||
ctx.textAlign = this.textAlign;
|
||||
|
|
@ -450,24 +404,22 @@
|
|||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
* @return {Number} Height of fabric.Text object
|
||||
*/
|
||||
_getTextHeight: function(ctx, textLines) {
|
||||
return this.fontSize * textLines.length * this.lineHeight;
|
||||
_getTextHeight: function() {
|
||||
return this._textLines.length * this._getHeightOfLine();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
* @return {Number} Maximum width of fabric.Text object
|
||||
*/
|
||||
_getTextWidth: function(ctx, textLines) {
|
||||
var maxWidth = ctx.measureText(textLines[0] || '|').width;
|
||||
_getTextWidth: function(ctx) {
|
||||
var maxWidth = this._getLineWidth(ctx, 0);
|
||||
|
||||
for (var i = 1, len = textLines.length; i < len; i++) {
|
||||
var currentLineWidth = ctx.measureText(textLines[i]).width;
|
||||
for (var i = 1, len = this._textLines.length; i < len; i++) {
|
||||
var currentLineWidth = this._getLineWidth(ctx, i);
|
||||
if (currentLineWidth > maxWidth) {
|
||||
maxWidth = currentLineWidth;
|
||||
}
|
||||
|
|
@ -498,7 +450,7 @@
|
|||
*/
|
||||
_renderTextLine: function(method, ctx, line, left, top, lineIndex) {
|
||||
// lift the line by quarter of fontSize
|
||||
top -= this.fontSize / 4;
|
||||
top -= this.fontSize * this._fontSizeFraction;
|
||||
|
||||
// short-circuit
|
||||
if (this.textAlign !== 'justify') {
|
||||
|
|
@ -506,7 +458,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
var lineWidth = ctx.measureText(line).width,
|
||||
var lineWidth = this._getLineWidth(ctx, i),
|
||||
totalWidth = this.width;
|
||||
|
||||
if (totalWidth > lineWidth) {
|
||||
|
|
@ -547,28 +499,27 @@
|
|||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextFill: function(ctx, textLines) {
|
||||
_renderTextFill: function(ctx) {
|
||||
if (!this.fill && !this._skipFillStrokeCheck) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._boundaries = [ ];
|
||||
var lineHeights = 0;
|
||||
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
var heightOfLine = this._getHeightOfLine(ctx, i, textLines);
|
||||
lineHeights += heightOfLine;
|
||||
for (var i = 0, len = this._textLines.length; i < len; i++) {
|
||||
var heightOfLine = this._getHeightOfLine(ctx, i),
|
||||
maxHeight = heightOfLine / this.lineHeight;
|
||||
|
||||
this._renderTextLine(
|
||||
'fillText',
|
||||
ctx,
|
||||
textLines[i],
|
||||
this._textLines[i],
|
||||
this._getLeftOffset(),
|
||||
this._getTopOffset() + lineHeights,
|
||||
this._getTopOffset() + lineHeights + maxHeight,
|
||||
i
|
||||
);
|
||||
lineHeights += heightOfLine;
|
||||
}
|
||||
if (this.shadow && !this.shadow.affectStroke) {
|
||||
this._removeShadow(ctx);
|
||||
|
|
@ -578,9 +529,8 @@
|
|||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextStroke: function(ctx, textLines) {
|
||||
_renderTextStroke: function(ctx) {
|
||||
if ((!this.stroke || this.strokeWidth === 0) && !this._skipFillStrokeCheck) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -588,6 +538,7 @@
|
|||
var lineHeights = 0;
|
||||
|
||||
ctx.save();
|
||||
|
||||
if (this.strokeDashArray) {
|
||||
// Spec requires the concatenation of two copies the dash list when the number of elements is odd
|
||||
if (1 & this.strokeDashArray.length) {
|
||||
|
|
@ -597,25 +548,26 @@
|
|||
}
|
||||
|
||||
ctx.beginPath();
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
var heightOfLine = this._getHeightOfLine(ctx, i, textLines);
|
||||
lineHeights += heightOfLine;
|
||||
for (var i = 0, len = this._textLines.length; i < len; i++) {
|
||||
var heightOfLine = this._getHeightOfLine(ctx, i),
|
||||
maxHeight = heightOfLine / this.lineHeight;
|
||||
|
||||
this._renderTextLine(
|
||||
'strokeText',
|
||||
ctx,
|
||||
textLines[i],
|
||||
this._textLines[i],
|
||||
this._getLeftOffset(),
|
||||
this._getTopOffset() + lineHeights,
|
||||
this._getTopOffset() + lineHeights + maxHeight,
|
||||
i
|
||||
);
|
||||
lineHeights += heightOfLine;
|
||||
}
|
||||
ctx.closePath();
|
||||
ctx.restore();
|
||||
},
|
||||
|
||||
_getHeightOfLine: function() {
|
||||
return this.fontSize * this.lineHeight;
|
||||
return this.fontSize * this._fontSizeMult * this.lineHeight;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -623,9 +575,9 @@
|
|||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextBackground: function(ctx, textLines) {
|
||||
_renderTextBackground: function(ctx) {
|
||||
this._renderTextBoxBackground(ctx);
|
||||
this._renderTextLinesBackground(ctx, textLines);
|
||||
this._renderTextLinesBackground(ctx);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -653,9 +605,9 @@
|
|||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextLinesBackground: function(ctx, textLines) {
|
||||
_renderTextLinesBackground: function(ctx) {
|
||||
var lineTopOffset = 0, heightOfLine = this._getHeightOfLine();
|
||||
if (!this.textBackgroundColor) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -663,20 +615,21 @@
|
|||
ctx.save();
|
||||
ctx.fillStyle = this.textBackgroundColor;
|
||||
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
for (var i = 0, len = this._textLines.length; i < len; i++) {
|
||||
|
||||
if (textLines[i] !== '') {
|
||||
if (this._textLines[i] !== '') {
|
||||
|
||||
var lineWidth = this._getLineWidth(ctx, textLines[i]),
|
||||
var lineWidth = this._getLineWidth(ctx, i),
|
||||
lineLeftOffset = this._getLineLeftOffset(lineWidth);
|
||||
|
||||
ctx.fillRect(
|
||||
this._getLeftOffset() + lineLeftOffset,
|
||||
this._getTopOffset() + (i * this.fontSize * this.lineHeight),
|
||||
this._getTopOffset() + lineTopOffset,
|
||||
lineWidth,
|
||||
this.fontSize * this.lineHeight
|
||||
this.fontSize * this._fontSizeMult
|
||||
);
|
||||
}
|
||||
lineTopOffset += heightOfLine;
|
||||
}
|
||||
ctx.restore();
|
||||
},
|
||||
|
|
@ -698,53 +651,85 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {String} line Text line
|
||||
* @return {Number} Line width
|
||||
*/
|
||||
_getLineWidth: function(ctx, line) {
|
||||
return this.textAlign === 'justify'
|
||||
? this.width
|
||||
: ctx.measureText(line).width;
|
||||
_clearCache: function() {
|
||||
this.__lineWidths = [ ];
|
||||
this.__lineHeights = [ ];
|
||||
this.__lineOffsets = [ ];
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_shouldClearCache: function() {
|
||||
var shouldClear = false;
|
||||
for (var prop in this._dimensionAffectingProps) {
|
||||
if (this['__' + prop] !== this[prop]) {
|
||||
this['__' + prop] = this[prop];
|
||||
shouldClear = true;
|
||||
}
|
||||
}
|
||||
return shouldClear;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
* @return {Number} Line width
|
||||
*/
|
||||
_renderTextDecoration: function(ctx, textLines) {
|
||||
_getLineWidth: function(ctx, lineIndex) {
|
||||
if (this.__lineWidths[lineIndex]) {
|
||||
return this.__lineWidths[lineIndex];
|
||||
}
|
||||
this.__lineWidths[lineIndex] = this.textAlign === 'justify' ?
|
||||
this.width : ctx.measureText(this._textLines[lineIndex]).width;
|
||||
return this.__lineWidths[lineIndex];
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_renderTextDecoration: function(ctx) {
|
||||
if (!this.textDecoration) {
|
||||
return;
|
||||
}
|
||||
|
||||
// var halfOfVerticalBox = this.originY === 'top' ? 0 : this._getTextHeight(ctx, textLines) / 2;
|
||||
var halfOfVerticalBox = this._getTextHeight(ctx, textLines) / 2,
|
||||
_this = this;
|
||||
var halfOfVerticalBox = this.height / 2,
|
||||
_this = this, offsets = [];
|
||||
|
||||
/** @ignore */
|
||||
function renderLinesAtOffset(offset) {
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
function renderLinesAtOffset(offsets) {
|
||||
var i, lineHeight = 0, len, j, oLen;
|
||||
for (i = 0, len = _this._textLines.length; i < len; i++) {
|
||||
|
||||
var lineWidth = _this._getLineWidth(ctx, textLines[i]),
|
||||
lineLeftOffset = _this._getLineLeftOffset(lineWidth);
|
||||
var lineWidth = _this._getLineWidth(ctx, i),
|
||||
lineLeftOffset = _this._getLineLeftOffset(lineWidth),
|
||||
heightOfLine = _this._getHeightOfLine(ctx, i);
|
||||
|
||||
ctx.fillRect(
|
||||
_this._getLeftOffset() + lineLeftOffset,
|
||||
~~((offset + (i * _this._getHeightOfLine(ctx, i, textLines))) - halfOfVerticalBox),
|
||||
lineWidth,
|
||||
1);
|
||||
for (j = 0, oLen = offsets.length; j < oLen; j++) {
|
||||
ctx.fillRect(
|
||||
_this._getLeftOffset() + lineLeftOffset,
|
||||
lineHeight + (_this._fontSizeMult - 1 + offsets[j] ) * _this.fontSize - halfOfVerticalBox,
|
||||
lineWidth,
|
||||
_this.fontSize / 15);
|
||||
}
|
||||
lineHeight += heightOfLine;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.textDecoration.indexOf('underline') > -1) {
|
||||
renderLinesAtOffset(this.fontSize * this.lineHeight);
|
||||
offsets.push(0.85); // 1 - 3/16
|
||||
}
|
||||
if (this.textDecoration.indexOf('line-through') > -1) {
|
||||
renderLinesAtOffset(this.fontSize * this.lineHeight - this.fontSize / 2);
|
||||
offsets.push(0.43);
|
||||
}
|
||||
if (this.textDecoration.indexOf('overline') > -1) {
|
||||
renderLinesAtOffset(this.fontSize * this.lineHeight - this.fontSize);
|
||||
offsets.push(-0.12);
|
||||
}
|
||||
|
||||
if (offsets.length > 0) {
|
||||
renderLinesAtOffset(offsets);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -772,10 +757,19 @@
|
|||
}
|
||||
|
||||
ctx.save();
|
||||
this._setTextStyles(ctx);
|
||||
|
||||
if (this._shouldClearCache()) {
|
||||
this._clearCache();
|
||||
this._textLines = this.text.split(this._reNewline);
|
||||
this.width = this._getTextWidth(ctx);
|
||||
this.height = this._getTextHeight(ctx);
|
||||
}
|
||||
if (!noTransform) {
|
||||
this.transform(ctx);
|
||||
}
|
||||
|
||||
this._setStrokeStyles(ctx);
|
||||
this._setFillStyles(ctx);
|
||||
var isInPathGroup = this.group && this.group.type === 'path-group';
|
||||
|
||||
if (isInPathGroup) {
|
||||
|
|
@ -806,9 +800,7 @@
|
|||
lineHeight: this.lineHeight,
|
||||
textDecoration: this.textDecoration,
|
||||
textAlign: this.textAlign,
|
||||
path: this.path,
|
||||
textBackgroundColor: this.textBackgroundColor,
|
||||
useNative: this.useNative
|
||||
textBackgroundColor: this.textBackgroundColor
|
||||
});
|
||||
if (!this.includeDefaultValues) {
|
||||
this._removeDefaultValues(object);
|
||||
|
|
@ -823,16 +815,10 @@
|
|||
* @return {String} svg representation of an instance
|
||||
*/
|
||||
toSVG: function(reviver) {
|
||||
var markup = [ ],
|
||||
textLines = this.text.split(this._reNewline),
|
||||
offsets = this._getSVGLeftTopOffsets(textLines),
|
||||
textAndBg = this._getSVGTextAndBg(offsets.lineTop, offsets.textLeft, textLines),
|
||||
shadowSpans = this._getSVGShadows(offsets.lineTop, textLines);
|
||||
|
||||
// move top offset by an ascent
|
||||
offsets.textTop += (this._fontAscent ? ((this._fontAscent / 5) * this.lineHeight) : 0);
|
||||
|
||||
this._wrapSVGTextAndBg(markup, textAndBg, shadowSpans, offsets);
|
||||
var markup = this._createBaseSVGMarkup(),
|
||||
offsets = this._getSVGLeftTopOffsets(this.ctx),
|
||||
textAndBg = this._getSVGTextAndBg(offsets.textTop, offsets.textLeft);
|
||||
this._wrapSVGTextAndBg(markup, textAndBg);
|
||||
|
||||
return reviver ? reviver(markup.join('')) : markup.join('');
|
||||
},
|
||||
|
|
@ -840,19 +826,14 @@
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
_getSVGLeftTopOffsets: function(textLines) {
|
||||
var lineTop = this.useNative
|
||||
? this.fontSize * this.lineHeight
|
||||
: (-this._fontAscent - ((this._fontAscent / 5) * this.lineHeight)),
|
||||
|
||||
textLeft = -(this.width/2),
|
||||
textTop = this.useNative
|
||||
? (this.fontSize * this.lineHeight - 0.25 * this.fontSize) // to lift by 1 / 4 of font height.
|
||||
: (this.height/2) - (textLines.length * this.fontSize) - this._totalLineHeight;
|
||||
_getSVGLeftTopOffsets: function(ctx) {
|
||||
var lineTop = this._getHeightOfLine(ctx, 0),
|
||||
textLeft = -this.width / 2,
|
||||
textTop = 0;
|
||||
|
||||
return {
|
||||
textLeft: textLeft + (this.group && this.group.type === 'path-group' ? this.left : 0),
|
||||
textTop: textTop + (this.group && this.group.type === 'path-group' ? this.top : 0),
|
||||
textTop: textTop + (this.group && this.group.type === 'path-group' ? -this.top : 0),
|
||||
lineTop: lineTop
|
||||
};
|
||||
},
|
||||
|
|
@ -860,99 +841,43 @@
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
_wrapSVGTextAndBg: function(markup, textAndBg, shadowSpans, offsets) {
|
||||
_wrapSVGTextAndBg: function(markup, textAndBg) {
|
||||
markup.push(
|
||||
'<g transform="', this.getSvgTransform(), this.getSvgTransformMatrix(), '">\n',
|
||||
'\t<g transform="', this.getSvgTransform(), this.getSvgTransformMatrix(), '">\n',
|
||||
textAndBg.textBgRects.join(''),
|
||||
'<text ',
|
||||
'\t\t<text ',
|
||||
(this.fontFamily ? 'font-family="' + this.fontFamily.replace(/"/g, '\'') + '" ': ''),
|
||||
(this.fontSize ? 'font-size="' + this.fontSize + '" ': ''),
|
||||
(this.fontStyle ? 'font-style="' + this.fontStyle + '" ': ''),
|
||||
(this.fontWeight ? 'font-weight="' + this.fontWeight + '" ': ''),
|
||||
(this.textDecoration ? 'text-decoration="' + this.textDecoration + '" ': ''),
|
||||
'style="', this.getSvgStyles(), '" ',
|
||||
/* svg starts from left/bottom corner so we normalize height */
|
||||
'transform="translate(', toFixed(offsets.textLeft, 2), ' ', toFixed(offsets.textTop, 2), ')">',
|
||||
shadowSpans.join(''),
|
||||
'style="', this.getSvgStyles(), '" >',
|
||||
textAndBg.textSpans.join(''),
|
||||
'</text>\n',
|
||||
'</g>\n'
|
||||
'\t</g>\n'
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Number} lineHeight
|
||||
* @param {Array} textLines Array of all text lines
|
||||
* @return {Array}
|
||||
*/
|
||||
_getSVGShadows: function(lineHeight, textLines) {
|
||||
var shadowSpans = [],
|
||||
i, len,
|
||||
lineTopOffsetMultiplier = 1;
|
||||
|
||||
if (!this.shadow || !this._boundaries) {
|
||||
return shadowSpans;
|
||||
}
|
||||
|
||||
for (i = 0, len = textLines.length; i < len; i++) {
|
||||
if (textLines[i] !== '') {
|
||||
var lineLeftOffset = (this._boundaries && this._boundaries[i]) ? this._boundaries[i].left : 0;
|
||||
shadowSpans.push(
|
||||
'<tspan x="',
|
||||
toFixed((lineLeftOffset + lineTopOffsetMultiplier) + this.shadow.offsetX, 2),
|
||||
((i === 0 || this.useNative) ? '" y' : '" dy'), '="',
|
||||
toFixed(this.useNative
|
||||
? ((lineHeight * i) - this.height / 2 + this.shadow.offsetY)
|
||||
: (lineHeight + (i === 0 ? this.shadow.offsetY : 0)), 2),
|
||||
'" ',
|
||||
this._getFillAttributes(this.shadow.color), '>',
|
||||
fabric.util.string.escapeXml(textLines[i]),
|
||||
'</tspan>');
|
||||
lineTopOffsetMultiplier = 1;
|
||||
}
|
||||
else {
|
||||
// in some environments (e.g. IE 7 & 8) empty tspans are completely ignored, using a lineTopOffsetMultiplier
|
||||
// prevents empty tspans
|
||||
lineTopOffsetMultiplier++;
|
||||
}
|
||||
}
|
||||
|
||||
return shadowSpans;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Number} lineHeight
|
||||
* @param {Number} textTopOffset Text top offset
|
||||
* @param {Number} textLeftOffset Text left offset
|
||||
* @param {Array} textLines Array of all text lines
|
||||
* @return {Object}
|
||||
*/
|
||||
_getSVGTextAndBg: function(lineHeight, textLeftOffset, textLines) {
|
||||
_getSVGTextAndBg: function(textTopOffset, textLeftOffset) {
|
||||
var textSpans = [ ],
|
||||
textBgRects = [ ],
|
||||
lineTopOffsetMultiplier = 1;
|
||||
|
||||
height = 0;
|
||||
// bounding-box background
|
||||
this._setSVGBg(textBgRects);
|
||||
|
||||
// text and text-background
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
if (textLines[i] !== '') {
|
||||
this._setSVGTextLineText(textLines[i], i, textSpans, lineHeight, lineTopOffsetMultiplier, textBgRects);
|
||||
lineTopOffsetMultiplier = 1;
|
||||
for (var i = 0, len = this._textLines.length; i < len; i++) {
|
||||
if (this.textBackgroundColor) {
|
||||
this._setSVGTextLineBg(textBgRects, i, textLeftOffset, textTopOffset, height);
|
||||
}
|
||||
else {
|
||||
// in some environments (e.g. IE 7 & 8) empty tspans are completely ignored, using a lineTopOffsetMultiplier
|
||||
// prevents empty tspans
|
||||
lineTopOffsetMultiplier++;
|
||||
}
|
||||
|
||||
if (!this.textBackgroundColor || !this._boundaries) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this._setSVGTextLineBg(textBgRects, i, textLeftOffset, lineHeight);
|
||||
this._setSVGTextLineText(i, textSpans, height, textLeftOffset, textTopOffset, textBgRects);
|
||||
height += this._getHeightOfLine(this.ctx, i);
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -961,56 +886,52 @@
|
|||
};
|
||||
},
|
||||
|
||||
_setSVGTextLineText: function(textLine, i, textSpans, lineHeight, lineTopOffsetMultiplier) {
|
||||
var lineLeftOffset = (this._boundaries && this._boundaries[i])
|
||||
? toFixed(this._boundaries[i].left, 2)
|
||||
: 0;
|
||||
|
||||
_setSVGTextLineText: function(i, textSpans, height, textLeftOffset, textTopOffset) {
|
||||
var yPos = this.fontSize * (this._fontSizeMult - this._fontSizeFraction)
|
||||
- textTopOffset + height - this.height / 2;
|
||||
textSpans.push(
|
||||
'<tspan x="',
|
||||
lineLeftOffset, '" ',
|
||||
(i === 0 || this.useNative ? 'y' : 'dy'), '="',
|
||||
toFixed(this.useNative
|
||||
? ((lineHeight * i) - this.height / 2)
|
||||
: (lineHeight * lineTopOffsetMultiplier), 2), '" ',
|
||||
toFixed(textLeftOffset + this._getLineLeftOffset(this.__lineWidths[i]), 4), '" ',
|
||||
'y="',
|
||||
toFixed(yPos, 4),
|
||||
'" ',
|
||||
// doing this on <tspan> elements since setting opacity
|
||||
// on containing <text> one doesn't work in Illustrator
|
||||
this._getFillAttributes(this.fill), '>',
|
||||
fabric.util.string.escapeXml(textLine),
|
||||
fabric.util.string.escapeXml(this._textLines[i]),
|
||||
'</tspan>'
|
||||
);
|
||||
},
|
||||
|
||||
_setSVGTextLineBg: function(textBgRects, i, textLeftOffset, lineHeight) {
|
||||
_setSVGTextLineBg: function(textBgRects, i, textLeftOffset, textTopOffset, height) {
|
||||
textBgRects.push(
|
||||
'<rect ',
|
||||
'\t\t<rect ',
|
||||
this._getFillAttributes(this.textBackgroundColor),
|
||||
' x="',
|
||||
toFixed(textLeftOffset + this._boundaries[i].left, 2),
|
||||
toFixed(textLeftOffset + this._getLineLeftOffset(this.__lineWidths[i]), 4),
|
||||
'" y="',
|
||||
/* an offset that seems to straighten things out */
|
||||
toFixed((lineHeight * i) - this.height / 2, 2),
|
||||
toFixed(height - this.height / 2, 4),
|
||||
'" width="',
|
||||
toFixed(this._boundaries[i].width, 2),
|
||||
toFixed(this.__lineWidths[i], 4),
|
||||
'" height="',
|
||||
toFixed(this._boundaries[i].height, 2),
|
||||
toFixed(this._getHeightOfLine(this.ctx, i) / this.lineHeight, 4),
|
||||
'"></rect>\n');
|
||||
},
|
||||
|
||||
_setSVGBg: function(textBgRects) {
|
||||
if (this.backgroundColor && this._boundaries) {
|
||||
if (this.backgroundColor) {
|
||||
textBgRects.push(
|
||||
'<rect ',
|
||||
'\t\t<rect ',
|
||||
this._getFillAttributes(this.backgroundColor),
|
||||
' x="',
|
||||
toFixed(-this.width / 2, 2),
|
||||
toFixed(-this.width / 2, 4),
|
||||
'" y="',
|
||||
toFixed(-this.height / 2, 2),
|
||||
toFixed(-this.height / 2, 4),
|
||||
'" width="',
|
||||
toFixed(this.width, 2),
|
||||
toFixed(this.width, 4),
|
||||
'" height="',
|
||||
toFixed(this.height, 2),
|
||||
'"></rect>');
|
||||
toFixed(this.height, 4),
|
||||
'"></rect>\n');
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -1039,9 +960,6 @@
|
|||
* @chainable
|
||||
*/
|
||||
_set: function(key, value) {
|
||||
if (key === 'fontFamily' && this.path) {
|
||||
this.path = this.path.replace(/(.*?)([^\/]*)(\.font\.js)/, '$1' + value + '$3');
|
||||
}
|
||||
this.callSuper('_set', key, value);
|
||||
|
||||
if (key in this._dimensionAffectingProps) {
|
||||
|
|
@ -1107,7 +1025,6 @@
|
|||
if (!options.originX) {
|
||||
options.originX = 'left';
|
||||
}
|
||||
options.top += options.fontSize / 4;
|
||||
var text = new fabric.Text(element.textContent, options),
|
||||
/*
|
||||
Adjust positioning:
|
||||
|
|
@ -1124,7 +1041,7 @@
|
|||
}
|
||||
text.set({
|
||||
left: text.getLeft() + offX,
|
||||
top: text.getTop() - text.getHeight() / 2
|
||||
top: text.getTop() - text.getHeight() / 2 + text.fontSize * (0.18 + text._fontSizeFraction) /* 0.3 is the old lineHeight */
|
||||
});
|
||||
|
||||
return text;
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
fabric.util.object.extend(fabric.Text.prototype, {
|
||||
_renderViaCufon: function(ctx) {
|
||||
|
||||
var o = Cufon.textOptions || (Cufon.textOptions = { });
|
||||
|
||||
// export options to be used by cufon.js
|
||||
o.left = this.left;
|
||||
o.top = this.top;
|
||||
o.context = ctx;
|
||||
o.color = this.fill;
|
||||
|
||||
var el = this._initDummyElementForCufon();
|
||||
|
||||
// set "cursor" to top/left corner
|
||||
this.transform(ctx);
|
||||
|
||||
// draw text
|
||||
Cufon.replaceElement(el, {
|
||||
engine: 'canvas',
|
||||
separate: 'none',
|
||||
fontFamily: this.fontFamily,
|
||||
fontWeight: this.fontWeight,
|
||||
textDecoration: this.textDecoration,
|
||||
textShadow: this.shadow && this.shadow.toString(),
|
||||
textAlign: this.textAlign,
|
||||
fontStyle: this.fontStyle,
|
||||
lineHeight: this.lineHeight,
|
||||
stroke: this.stroke,
|
||||
strokeWidth: this.strokeWidth,
|
||||
backgroundColor: this.backgroundColor,
|
||||
textBackgroundColor: this.textBackgroundColor
|
||||
});
|
||||
|
||||
// update width, height
|
||||
this.width = o.width;
|
||||
this.height = o.height;
|
||||
|
||||
this._totalLineHeight = o.totalLineHeight;
|
||||
this._fontAscent = o.fontAscent;
|
||||
this._boundaries = o.boundaries;
|
||||
|
||||
el = null;
|
||||
|
||||
// need to set coords _after_ the width/height was retreived from Cufon
|
||||
this.setCoords();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_initDummyElementForCufon: function() {
|
||||
var el = fabric.document.createElement('pre'),
|
||||
container = fabric.document.createElement('div');
|
||||
|
||||
// Cufon doesn't play nice with textDecoration=underline if element doesn't have a parent
|
||||
container.appendChild(el);
|
||||
|
||||
//jscs:disable requireCamelCaseOrUpperCaseIdentifiers
|
||||
if (typeof G_vmlCanvasManager === 'undefined') {
|
||||
el.innerHTML = this.text;
|
||||
}
|
||||
//jscs:enable requireCamelCaseOrUpperCaseIdentifiers
|
||||
else {
|
||||
// IE 7 & 8 drop newlines and white space on text nodes
|
||||
// see: http://web.student.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
|
||||
// see: http://www.w3schools.com/dom/dom_mozilla_vs_ie.asp
|
||||
el.innerText = this.text.replace(/\r?\n/gi, '\r');
|
||||
}
|
||||
|
||||
el.style.fontSize = this.fontSize + 'px';
|
||||
el.style.letterSpacing = 'normal';
|
||||
|
||||
return el;
|
||||
}
|
||||
});
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
'left': 0,
|
||||
'top': 0,
|
||||
'width': 20,
|
||||
'height': 52,
|
||||
'height': 58.76,
|
||||
'fill': 'rgb(0,0,0)',
|
||||
'stroke': null,
|
||||
'strokeWidth': 1,
|
||||
|
|
@ -34,10 +34,8 @@
|
|||
'lineHeight': 1.3,
|
||||
'textDecoration': '',
|
||||
'textAlign': 'left',
|
||||
'path': null,
|
||||
'backgroundColor': '',
|
||||
'textBackgroundColor': '',
|
||||
'useNative': true,
|
||||
'fillRule': 'nonzero',
|
||||
'globalCompositeOperation': 'source-over',
|
||||
styles: { }
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
'left': 0,
|
||||
'top': 0,
|
||||
'width': CHAR_WIDTH,
|
||||
'height': 52,
|
||||
'height': 52.43,
|
||||
'fill': 'rgb(0,0,0)',
|
||||
'stroke': null,
|
||||
'strokeWidth': 1,
|
||||
|
|
@ -38,17 +38,15 @@
|
|||
'fontWeight': 'normal',
|
||||
'fontFamily': 'Times New Roman',
|
||||
'fontStyle': '',
|
||||
'lineHeight': 1.3,
|
||||
'lineHeight': 1.16,
|
||||
'textDecoration': '',
|
||||
'textAlign': 'left',
|
||||
'path': null,
|
||||
'textBackgroundColor': '',
|
||||
'useNative': true,
|
||||
'fillRule': 'nonzero',
|
||||
'globalCompositeOperation': 'source-over'
|
||||
};
|
||||
|
||||
var TEXT_SVG = '<g transform="translate(10 26)">\n<text font-family="Times New Roman" font-size="40" font-weight="normal" style="stroke: none; stroke-width: 1; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform="translate(-10 42)"><tspan x="0" y="-26" fill="rgb(0,0,0)">x</tspan></text>\n</g>\n';
|
||||
var TEXT_SVG = '\t<g transform="translate(10 26.22)">\n\t\t<text font-family="Times New Roman" font-size="40" font-weight="normal" style="stroke: none; stroke-width: 1; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" ><tspan x="-10" y="8.984" fill="rgb(0,0,0)">x</tspan></text>\n\t</g>\n';
|
||||
|
||||
test('constructor', function() {
|
||||
ok(fabric.Text);
|
||||
|
|
@ -156,9 +154,9 @@
|
|||
|
||||
var expectedObject = fabric.util.object.extend(fabric.util.object.clone(REFERENCE_TEXT_OBJECT), {
|
||||
left: 4,
|
||||
top: -6.4,
|
||||
top: -3.61,
|
||||
width: 8,
|
||||
height: 20.8,
|
||||
height: 20.97,
|
||||
fontSize: 16,
|
||||
originX: 'left'
|
||||
});
|
||||
|
|
@ -197,9 +195,9 @@
|
|||
var expectedObject = fabric.util.object.extend(fabric.util.object.clone(REFERENCE_TEXT_OBJECT), {
|
||||
/* left varies slightly due to node-canvas rendering */
|
||||
left: fabric.util.toFixed(textWithAttrs.left + '', 2),
|
||||
top: -29.2,
|
||||
top: -7.72,
|
||||
width: CHAR_WIDTH,
|
||||
height: 159.9,
|
||||
height: 161.23,
|
||||
fill: 'rgb(255,255,255)',
|
||||
opacity: 0.45,
|
||||
stroke: 'blue',
|
||||
|
|
|
|||
Loading…
Reference in a new issue