From 350261437a992d7ed52468c3b7cdd5e0c9fe7cad Mon Sep 17 00:00:00 2001 From: GordoRank Date: Tue, 14 Jan 2014 17:09:19 +0000 Subject: [PATCH 1/3] Rewrite renderSelection to only draw once per line Previously RenderSelection performed a fillRect() command for every character. This resulted in poor performance on large bodies of text. This rewrite calculates the selection box for each line of text and draws a single rectangle for each line, dramatically improving performance. --- src/shapes/itext.class.js | 66 +++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/src/shapes/itext.class.js b/src/shapes/itext.class.js index cd244517..a8be69e4 100644 --- a/src/shapes/itext.class.js +++ b/src/shapes/itext.class.js @@ -510,40 +510,46 @@ ctx.fillStyle = this.selectionColor; - var cursorLocation = this.get2DCursorLocation(), - lineIndex = cursorLocation.lineIndex, - charIndex = cursorLocation.charIndex, - textLines = this.text.split(this._reNewline), - origLineIndex = lineIndex; + var start = this.get2DCursorLocation(this.selectionStart), + end = this.get2DCursorLocation(this.selectionEnd), + textLines = this.text.split(this._reNewline), + charIndex = start.charIndex - textLines[0].length; - for (var i = this.selectionStart; i < this.selectionEnd; i++) { + for(var i = start.lineIndex; i <= end.lineIndex; i++){ + var lineOffset = this._getCachedLineOffset(i, textLines) || 0, + lineHeight = this._getCachedLineHeight(i), + boxWidth = 0; - if (chars[i] === '\n') { - boundaries.leftOffset = 0; - boundaries.topOffset += this._getHeightOfLine(ctx, lineIndex); - lineIndex++; - charIndex = 0; - } - else if (i !== this.text.length) { + if (i == start.lineIndex) { + for (var j = 0, len = textLines[i].length; j < len; j++) { + if (j >= start.charIndex && (i !== end.lineIndex || j < end.charIndex)) { + boxWidth += this._getWidthOfChar(ctx, textLines[i][j], i, charIndex); + } + if (j < start.charIndex) { + lineOffset += this._getWidthOfChar(ctx, textLines[i][j], i, charIndex); + } + charIndex++; + } + } + else if (i > start.lineIndex && i < end.lineIndex) { + boxWidth += this._getCachedLineWidth(i, textLines) || 5; + charIndex += textLines[i].length; + } + else if (i == end.lineIndex) { + for (var j = 0, len = end.charIndex; j < len; j++) { + boxWidth += this._getWidthOfChar(ctx, textLines[i][j], i, charIndex); + charIndex++; + } + } - var charWidth = this._getWidthOfChar(ctx, chars[i], lineIndex, charIndex), - lineOffset = this._getLineLeftOffset(this._getWidthOfLine(ctx, lineIndex, textLines)) || 0; + ctx.fillRect( + boundaries.left + lineOffset, + boundaries.top + boundaries.topOffset, + boxWidth, + lineHeight); - if (lineIndex === origLineIndex) { - // only offset the line if we're rendering selection of 2nd, 3rd, etc. line - lineOffset = 0; - } - - ctx.fillRect( - boundaries.left + boundaries.leftOffset + lineOffset, - boundaries.top + boundaries.topOffset, - charWidth, - this._getHeightOfLine(ctx, lineIndex)); - - boundaries.leftOffset += charWidth; - charIndex++; - } - } + boundaries.topOffset += lineHeight; + } ctx.restore(); }, From 9f2c678a660982d6f24231ed0c28b3ab3bc4d0a8 Mon Sep 17 00:00:00 2001 From: GordoRank Date: Tue, 14 Jan 2014 17:23:40 +0000 Subject: [PATCH 2/3] Formatting fixed and end.lineIndex cached --- src/shapes/itext.class.js | 74 +++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/shapes/itext.class.js b/src/shapes/itext.class.js index a8be69e4..f3ac2fcc 100644 --- a/src/shapes/itext.class.js +++ b/src/shapes/itext.class.js @@ -510,46 +510,46 @@ ctx.fillStyle = this.selectionColor; - var start = this.get2DCursorLocation(this.selectionStart), - end = this.get2DCursorLocation(this.selectionEnd), - textLines = this.text.split(this._reNewline), - charIndex = start.charIndex - textLines[0].length; + var start = this.get2DCursorLocation(this.selectionStart), + end = this.get2DCursorLocation(this.selectionEnd), + textLines = this.text.split(this._reNewline), + charIndex = start.charIndex - textLines[0].length; - for(var i = start.lineIndex; i <= end.lineIndex; i++){ - var lineOffset = this._getCachedLineOffset(i, textLines) || 0, - lineHeight = this._getCachedLineHeight(i), - boxWidth = 0; + for(var i = start.lineIndex, lineCount = end.lineIndex; i <= lineCount; i++){ + var lineOffset = this._getCachedLineOffset(i, textLines) || 0, + lineHeight = this._getCachedLineHeight(i), + boxWidth = 0; - if (i == start.lineIndex) { - for (var j = 0, len = textLines[i].length; j < len; j++) { - if (j >= start.charIndex && (i !== end.lineIndex || j < end.charIndex)) { - boxWidth += this._getWidthOfChar(ctx, textLines[i][j], i, charIndex); - } - if (j < start.charIndex) { - lineOffset += this._getWidthOfChar(ctx, textLines[i][j], i, charIndex); - } - charIndex++; - } - } - else if (i > start.lineIndex && i < end.lineIndex) { - boxWidth += this._getCachedLineWidth(i, textLines) || 5; - charIndex += textLines[i].length; - } - else if (i == end.lineIndex) { - for (var j = 0, len = end.charIndex; j < len; j++) { - boxWidth += this._getWidthOfChar(ctx, textLines[i][j], i, charIndex); - charIndex++; - } - } - - ctx.fillRect( - boundaries.left + lineOffset, - boundaries.top + boundaries.topOffset, - boxWidth, - lineHeight); - - boundaries.topOffset += lineHeight; + if (i == start.lineIndex) { + for (var j = 0, len = textLines[i].length; j < len; j++) { + if (j >= start.charIndex && (i !== end.lineIndex || j < end.charIndex)) { + boxWidth += this._getWidthOfChar(ctx, textLines[i][j], i, charIndex); } + if (j < start.charIndex) { + lineOffset += this._getWidthOfChar(ctx, textLines[i][j], i, charIndex); + } + charIndex++; + } + } + else if (i > start.lineIndex && i < end.lineIndex) { + boxWidth += this._getCachedLineWidth(i, textLines) || 5; + charIndex += textLines[i].length; + } + else if (i == end.lineIndex) { + for (var j = 0, len = end.charIndex; j < len; j++) { + boxWidth += this._getWidthOfChar(ctx, textLines[i][j], i, charIndex); + charIndex++; + } + } + + ctx.fillRect( + boundaries.left + lineOffset, + boundaries.top + boundaries.topOffset, + boxWidth, + lineHeight); + + boundaries.topOffset += lineHeight; + } ctx.restore(); }, From 0abc547d6b8ad024795261d8b67262bdf2c9ffd8 Mon Sep 17 00:00:00 2001 From: GordoRank Date: Tue, 14 Jan 2014 17:37:40 +0000 Subject: [PATCH 3/3] Fixed formatting and cache start.lineIndex --- src/shapes/itext.class.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/shapes/itext.class.js b/src/shapes/itext.class.js index f3ac2fcc..e2cce7f0 100644 --- a/src/shapes/itext.class.js +++ b/src/shapes/itext.class.js @@ -512,17 +512,19 @@ var start = this.get2DCursorLocation(this.selectionStart), end = this.get2DCursorLocation(this.selectionEnd), + startLine = start.lineIndex, + endLine = end.lineIndex, textLines = this.text.split(this._reNewline), charIndex = start.charIndex - textLines[0].length; - for(var i = start.lineIndex, lineCount = end.lineIndex; i <= lineCount; i++){ + for (var i = startLine; i <= endLine; i++) { var lineOffset = this._getCachedLineOffset(i, textLines) || 0, lineHeight = this._getCachedLineHeight(i), boxWidth = 0; - if (i == start.lineIndex) { + if (i === startLine) { for (var j = 0, len = textLines[i].length; j < len; j++) { - if (j >= start.charIndex && (i !== end.lineIndex || j < end.charIndex)) { + if (j >= start.charIndex && (i !== endLine || j < end.charIndex)) { boxWidth += this._getWidthOfChar(ctx, textLines[i][j], i, charIndex); } if (j < start.charIndex) { @@ -531,11 +533,11 @@ charIndex++; } } - else if (i > start.lineIndex && i < end.lineIndex) { + else if (i > startLine && i < endLine) { boxWidth += this._getCachedLineWidth(i, textLines) || 5; charIndex += textLines[i].length; } - else if (i == end.lineIndex) { + else if (i === endLine) { for (var j = 0, len = end.charIndex; j < len; j++) { boxWidth += this._getWidthOfChar(ctx, textLines[i][j], i, charIndex); charIndex++;