@@ -124,6 +124,205 @@ var Text = new Class({
124124 this . originX = 1 ;
125125 } ,
126126
127+ /**
128+ * Greedy wrapping algorithm that will wrap words as the line grows longer than its horizontal
129+ * bounds.
130+ *
131+ * @param {string } text - The text to perform word wrap detection against.
132+ */
133+ runWordWrap : function ( text )
134+ {
135+ var style = this . style ;
136+ if ( style . wordWrapCallback )
137+ {
138+ var wrappedLines = style . wordWrapCallback . call ( style . wordWrapCallbackScope , text , this ) ;
139+ if ( Array . isArray ( wrappedLines ) )
140+ {
141+ wrappedLines = wrappedLines . join ( '\n' ) ;
142+ }
143+ return wrappedLines ;
144+ }
145+ else if ( style . wordWrapWidth )
146+ {
147+ if ( style . wordWrapUseAdvanced )
148+ {
149+ return this . advancedWordWrap ( text ) ;
150+ }
151+ else
152+ {
153+ return this . basicWordWrap ( text ) ;
154+ }
155+ }
156+ else
157+ {
158+ return text ;
159+ }
160+ } ,
161+
162+ /**
163+ * Advanced wrapping algorithm that will wrap words as the line grows longer than its horizontal
164+ * bounds. White space is condensed (e.g., consecutive spaces are replaced with one). Lines are
165+ * trimmed of white space before processing. Throws an error if the user was smart enough to
166+ * specify a wordWrapWidth less than a single character.
167+ *
168+ * @param {string } text - The text to perform word wrap detection against.
169+ */
170+ advancedWordWrap : function ( text )
171+ {
172+ var context = this . context ;
173+ var wordWrapWidth = this . style . wordWrapWidth ;
174+ var output = '' ;
175+
176+ // condense consecutive spaces and split into lines
177+ var lines = text
178+ . replace ( / + / gi, ' ' )
179+ . split ( / \r ? \n / gi) ;
180+
181+ var linesCount = lines . length ;
182+
183+ for ( var i = 0 ; i < linesCount ; i ++ )
184+ {
185+ var line = lines [ i ] ;
186+ var out = '' ;
187+
188+ // trim whitespace
189+ line = line . replace ( / ^ * | \s * $ / gi, '' ) ;
190+
191+ // if entire line is less than wordWrapWidth append the entire line and exit early
192+ var lineWidth = context . measureText ( line ) . width ;
193+
194+ if ( lineWidth < wordWrapWidth )
195+ {
196+ output += line + '\n' ;
197+ continue ;
198+ }
199+
200+ // otherwise, calculate new lines
201+ var currentLineWidth = wordWrapWidth ;
202+
203+ // split into words
204+ var words = line . split ( ' ' ) ;
205+
206+ for ( var j = 0 ; j < words . length ; j ++ )
207+ {
208+ var word = words [ j ] ;
209+ var wordWithSpace = word + ' ' ;
210+ var wordWidth = context . measureText ( wordWithSpace ) . width ;
211+
212+ if ( wordWidth > currentLineWidth )
213+ {
214+ // break word
215+ if ( j === 0 )
216+ {
217+ // shave off letters from word until it's small enough
218+ var newWord = wordWithSpace ;
219+
220+ while ( newWord . length )
221+ {
222+ newWord = newWord . slice ( 0 , - 1 ) ;
223+ wordWidth = context . measureText ( newWord ) . width ;
224+
225+ if ( wordWidth <= currentLineWidth )
226+ {
227+ break ;
228+ }
229+ }
230+
231+ // if wordWrapWidth is too small for even a single letter, shame user
232+ // failure with a fatal error
233+ if ( ! newWord . length )
234+ {
235+ throw new Error ( 'This text\'s wordWrapWidth setting is less than a single character!' ) ;
236+ }
237+
238+ // replace current word in array with remainder
239+ var secondPart = word . substr ( newWord . length ) ;
240+
241+ words [ j ] = secondPart ;
242+
243+ // append first piece to output
244+ out += newWord ;
245+ }
246+
247+ // if existing word length is 0, don't include it
248+ var offset = ( words [ j ] . length ) ? j : j + 1 ;
249+
250+ // collapse rest of sentence and remove any trailing white space
251+ var remainder = words . slice ( offset ) . join ( ' ' )
252+ . replace ( / [ \n ] * $ / gi, '' ) ;
253+
254+ // prepend remainder to next line
255+ lines [ i + 1 ] = remainder + ' ' + ( lines [ i + 1 ] || '' ) ;
256+ linesCount = lines . length ;
257+
258+ break ; // processing on this line
259+
260+ // append word with space to output
261+ }
262+ else
263+ {
264+ out += wordWithSpace ;
265+ currentLineWidth -= wordWidth ;
266+ }
267+ }
268+
269+ // append processed line to output
270+ output += out . replace ( / [ \n ] * $ / gi, '' ) + '\n' ;
271+ }
272+
273+ // trim the end of the string
274+ output = output . replace ( / [ \s | \n ] * $ / gi, '' ) ;
275+
276+ return output ;
277+ } ,
278+
279+ /**
280+ * Greedy wrapping algorithm that will wrap words as the line grows longer than its horizontal
281+ * bounds.
282+ *
283+ * @param {string } text - The text to perform word wrap detection against.
284+ */
285+ basicWordWrap : function ( text )
286+ {
287+ var result = '' ;
288+ var lines = text . split ( '\n' ) ;
289+
290+ for ( var i = 0 ; i < lines . length ; i ++ )
291+ {
292+ var spaceLeft = this . style . wordWrapWidth ;
293+ var words = lines [ i ] . split ( ' ' ) ;
294+
295+ for ( var j = 0 ; j < words . length ; j ++ )
296+ {
297+ var wordWidth = this . context . measureText ( words [ j ] ) . width ;
298+ var wordWidthWithSpace = wordWidth + this . context . measureText ( ' ' ) . width ;
299+
300+ if ( wordWidthWithSpace > spaceLeft )
301+ {
302+ // Skip printing the newline if it's the first word of the line that is greater
303+ // than the word wrap width.
304+ if ( j > 0 )
305+ {
306+ result += '\n' ;
307+ }
308+ result += words [ j ] + ' ' ;
309+ spaceLeft = this . style . wordWrapWidth - wordWidth ;
310+ }
311+ else
312+ {
313+ spaceLeft -= wordWidthWithSpace ;
314+ result += words [ j ] + ' ' ;
315+ }
316+ }
317+
318+ if ( i < lines . length - 1 )
319+ {
320+ result += '\n' ;
321+ }
322+ }
323+
324+ return result ;
325+ } ,
127326 setText : function ( value )
128327 {
129328 if ( Array . isArray ( value ) )
0 commit comments