@@ -0,0 +1,198 @@
// svg.textflow.js 0.8 - Copyright (c) 2013 Wout Fierens - Licensed under the MIT license
SVG . Textflow = function ( ) {
this . constructor . call ( this , SVG . create ( 'text' ) )
/* define default style */
this . styles = {
'font-size' : 16
, 'font-family' : 'Helvetica, Arial, sans-serif'
, 'text-anchor' : 'start'
}
/* initialize private variables */
this . _x = 0
this . _y = 0
this . _width = 100
this . _height = 100
this . _leading = 1.2
/* store type */
this . type = 'textflow'
}
// Inherit from SVG.Text
SVG . Textflow . prototype = new SVG . Text
// Add specific methods
SVG . extend ( SVG . Textflow , {
// Move over x-axis
x : function ( x , a ) {
/* act as getter */
if ( x == null )
return a ? this . attr ( 'x' ) : this . bbox ( ) . x
/* store x */
this . _x = x
return this . attr ( 'x' , x )
}
// Move over y-axis
, y : function ( y ) {
if ( y != null )
this . _y = y /= this . trans . scaleY
return this . attr ( 'y' , y )
}
// Update textflow content
, text : function ( text ) {
/* act as getter */
if ( text == null )
return this . content
/* update the content */
this . content = SVG . regex . test ( text , 'isBlank' ) ? 'text' : text
return this . attr ( 'x' , 0 ) . attr ( this . styles )
}
// Define textflow size
, size : function ( width , height ) {
this . _width = width
this . _height = height == null ? width : height
return this . build ( ) . move ( this . _x , this . _y )
}
// Build
, build : function ( ) {
var i , w , box , sandbox , span , line , words , word
, self = this
, lines = [ ]
, paragraphs = ( this . content || '' ) . split ( '\n' )
, size = this . styles [ 'font-size' ]
, tstyle = {
dy : this . _leading * size
, x : 0
, 'font-size' : size
, 'style' : 'font-size:' + size + ';'
}
/* remove existing lines */
this . clear ( )
this . data ( 'overflow' , null )
/* reset correction offset */
this . transform ( 'y' , 0 )
/* create temporary measuring sandbox */
sandbox = this . parent
. text ( 'well' )
. attr ( this . styles )
. move ( - 999999 , - 999999 )
/* parse paragraphs */
i = paragraphs . length
while ( i -- ) {
/* prepare line */
line = ''
words = paragraphs . shift ( ) . split ( ' ' )
/* add words */
w = words . length
while ( w -- ) {
word = words . shift ( )
/* try text */
sandbox . text ( line + word ) . attr ( tstyle )
/* measure width */
box = sandbox . bbox ( )
/* save line */
if ( box . width + size / 2 <= this . _width ) {
line += ( line . length > 0 ? ' ' : '' ) + word
} else {
lines . push ( line )
line = word
}
}
/* add last line */
lines . push ( line )
}
/* build textflow */
i = lines . length
while ( i -- ) {
/* check text height */
if ( this . bbox ( ) . height > this . _height ) {
if ( span )
this . node . removeChild ( span . node )
lines . unshift ( span . node . textContent )
break
}
/* create tspan */
// span = new SVG.TSpan().attr('xml:space', 'preserve', 'http://www.w3.org/XML/1998/namespace')
// this.node.appendChild(span.node)
// this.lines.push(span)
span = this . tspan ( '' ) . attr ( 'xml:space' , 'preserve' , 'http://www.w3.org/XML/1998/namespace' )
this . node . appendChild ( span . node )
this . lines . add ( span )
/* add text */
line = lines . shift ( )
span . text ( line == '' ? ' ' : line ) . attr ( tstyle )
}
/* remove last line if necessary */
if ( this . bbox ( ) . height > this . _height && span ) {
this . node . removeChild ( span . node )
lines . unshift ( span . node . textContent )
}
/* ensure correct visual position */
this . transform ( 'y' , - size * this . _base )
/* save overflow text */
this . data ( 'overflow' , lines . join ( ' ' ) , true )
/* remove measuring sandbox */
sandbox . remove ( )
/* HACK ALERT!!! this is a hack for chrome to render text properly. */
/* With @font-face chrome som e ti es re nder s t e xt li k e thi s */
this . style ( 'fill' , new SVG . Color ( this . attr ( 'fill' ) ) . brightness ( ) > 0.5 ? '#999' : '#333' )
setTimeout ( function ( ) {
self . style ( 'fill' , null )
} , 1 )
return this
}
// Rebuild
, rebuild : function ( a , v ) {
if ( [ 'font-size' , 'font-family' , 'leading' ] . indexOf ( a ) > - 1 )
this . build ( ) . move ( this . _x , this . attr ( 'y' ) )
else if ( a == 'text-anchor' )
this . transform ( 'x' , v == 'start' ? 0 : v == 'middle' ? this . _width / 2 : this . _width )
else if ( a == 'x' )
for ( var i = this . lines . length - 1 ; i >= 0 ; i -- )
this . lines [ i ] . attr ( a , v )
return this
}
} )
// Add textflow to container methods
SVG . extend ( SVG . Container , {
// Create textflow element
textflow : function ( text , width , height ) {
return this . put ( new SVG . Textflow ) . size ( width == null ? 100 : width , height == null ? 100 : height ) . text ( text )
}
} )