diff --git a/js/jquery.arctext.js b/js/jquery.arctext.js new file mode 100644 index 0000000..ed2586d --- /dev/null +++ b/js/jquery.arctext.js @@ -0,0 +1,381 @@ +/** + * Arctext.js + * A jQuery plugin for curved text + * http://www.codrops.com + * + * Copyright 2011, Pedro Botelho / Codrops + * Free to use under the MIT license. + * + * Date: Mon Jan 23 2012 + */ + +(function( $, undefined ) { + + /*! + * FitText.js 1.0 + * + * Copyright 2011, Dave Rupert http://daverupert.com + * Released under the WTFPL license + * http://sam.zoy.org/wtfpl/ + * + * Date: Thu May 05 14:23:00 2011 -0600 + */ + $.fn.fitText = function( kompressor, options ) { + + var settings = { + 'minFontSize' : Number.NEGATIVE_INFINITY, + 'maxFontSize' : Number.POSITIVE_INFINITY + }; + + return this.each(function() { + var $this = $(this); // store the object + var compressor = kompressor || 1; // set the compressor + + if ( options ) { + $.extend( settings, options ); + } + + // Resizer() resizes items based on the object width divided by the compressor * 10 + var resizer = function () { + $this.css('font-size', Math.max(Math.min($this.width() / (compressor*10), parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize))); + }; + + // Call once to set. + resizer(); + + // Call on resize. Opera debounces their resize by default. + $(window).resize(resizer); + }); + + }; + + /* + * Lettering plugin + * + * changed injector function: + * add for empty chars. + */ + function injector(t, splitter, klass, after) { + var a = t.text().split(splitter), inject = '', emptyclass; + if (a.length) { + $(a).each(function(i, item) { + emptyclass = ''; + if(item === ' ') { + emptyclass = ' empty'; + item=' '; + } + inject += '<span class="'+klass+(i+1)+emptyclass+'">'+item+'</span>'+after; + }); + t.empty().append(inject); + } + } + + var methods = { + init : function() { + + return this.each(function() { + injector($(this), '', 'char', ''); + }); + + }, + + words : function() { + + return this.each(function() { + injector($(this), ' ', 'word', ' '); + }); + + }, + + lines : function() { + + return this.each(function() { + var r = "eefec303079ad17405c889e092e105b0"; + // Because it's hard to split a <br/> tag consistently across browsers, + // (*ahem* IE *ahem*), we replaces all <br/> instances with an md5 hash + // (of the word "split"). If you're trying to use this plugin on that + // md5 hash string, it will fail because you're being ridiculous. + injector($(this).children("br").replaceWith(r).end(), r, 'line', ''); + }); + + } + }; + + $.fn.lettering = function( method ) { + // Method calling logic + if ( method && methods[method] ) { + return methods[ method ].apply( this, [].slice.call( arguments, 1 )); + } else if ( method === 'letters' || ! method ) { + return methods.init.apply( this, [].slice.call( arguments, 0 ) ); // always pass an array + } + $.error( 'Method ' + method + ' does not exist on jQuery.lettering' ); + return this; + }; + + /* + * Arctext object. + */ + $.Arctext = function( options, element ) { + + this.$el = $( element ); + this._init( options ); + + }; + + $.Arctext.defaults = { + radius : 0, // the minimum value allowed is half of the word length. if set to -1, the word will be straight. + dir : 1, // 1: curve is down, -1: curve is up. + rotate : true, // if true each letter will be rotated. + fitText : false // if you wanna try out the fitText plugin (http://fittextjs.com/) set this to true. Don't forget the wrapper should be fluid. + }; + + $.Arctext.prototype = { + _init : function( options ) { + + this.options = $.extend( true, {}, $.Arctext.defaults, options ); + + // apply the lettering plugin. + this._applyLettering(); + + this.$el.data( 'arctext', true ); + + // calculate values + this._calc(); + + // apply transformation. + this._rotateWord(); + + // load the events + this._loadEvents(); + + }, + _applyLettering : function() { + + this.$el.lettering(); + + if( this.options.fitText ) + this.$el.fitText(); + + this.$letters = this.$el.find('span').css('display', 'inline-block'); + + }, + _calc : function() { + + if( this.options.radius === -1 ) + return false; + + // calculate word / arc sizes & distances. + this._calcBase(); + + // get final values for each letter. + this._calcLetters(); + + }, + _calcBase : function() { + + // total word width (sum of letters widths) + this.dtWord = 0; + + var _self = this; + + this.$letters.each( function(i) { + + var $letter = $(this), + letterWidth = $letter.outerWidth( true ); + + _self.dtWord += letterWidth; + + // save the center point of each letter: + $letter.data( 'center', _self.dtWord - letterWidth / 2 ); + + }); + + // the middle point of the word. + var centerWord = this.dtWord / 2; + + // check radius : the minimum value allowed is half of the word length. + if( this.options.radius < centerWord ) + this.options.radius = centerWord; + + // total arc segment length, where the letters will be placed. + this.dtArcBase = this.dtWord; + + // calculate the arc (length) that goes from the beginning of the first letter (x=0) to the end of the last letter (x=this.dtWord). + // first lets calculate the angle for the triangle with base = this.dtArcBase and the other two sides = radius. + var angle = 2 * Math.asin( this.dtArcBase / ( 2 * this.options.radius ) ); + + // given the formula: L(ength) = R(adius) x A(ngle), we calculate our arc length. + this.dtArc = this.options.radius * angle; + + }, + _calcLetters : function() { + + var _self = this, + iteratorX = 0; + + this.$letters.each( function(i) { + + var $letter = $(this), + // calculate each letter's semi arc given the percentage of each letter on the original word. + dtArcLetter = ( $letter.outerWidth( true ) / _self.dtWord ) * _self.dtArc, + // angle for the dtArcLetter given our radius. + beta = dtArcLetter / _self.options.radius, + // distance from the middle point of the semi arc's chord to the center of the circle. + // this is going to be the place where the letter will be positioned. + h = _self.options.radius * ( Math.cos( beta / 2 ) ), + // angle formed by the x-axis and the left most point of the chord. + alpha = Math.acos( ( _self.dtWord / 2 - iteratorX ) / _self.options.radius ), + // angle formed by the x-axis and the right most point of the chord. + theta = alpha + beta / 2, + // distances of the sides of the triangle formed by h and the orthogonal to the x-axis. + x = Math.cos( theta ) * h, + y = Math.sin( theta ) * h, + // the value for the coordinate x of the middle point of the chord. + xpos = iteratorX + Math.abs( _self.dtWord / 2 - x - iteratorX ), + // finally, calculate how much to translate each letter, given its center point. + // also calculate the angle to rotate the letter accordingly. + xval = 0| xpos - $letter.data( 'center' ), + yval = 0| _self.options.radius - y, + angle = ( _self.options.rotate ) ? 0| -Math.asin( x / _self.options.radius ) * ( 180 / Math.PI ) : 0; + + // the iteratorX will be positioned on the second point of each semi arc + iteratorX = 2 * xpos - iteratorX; + + // save these values + $letter.data({ + x : xval, + y : ( _self.options.dir === 1 ) ? yval : -yval, + a : ( _self.options.dir === 1 ) ? angle : -angle + }); + + }); + + }, + _rotateWord : function( animation ) { + + if( !this.$el.data('arctext') ) return false; + + var _self = this; + + this.$letters.each( function(i) { + + var $letter = $(this), + transformation = ( _self.options.radius === -1 ) ? 'none' : 'translateX(' + $letter.data('x') + 'px) translateY(' + $letter.data('y') + 'px) rotate(' + $letter.data('a') + 'deg)', + transition = ( animation ) ? 'all ' + ( animation.speed || 0 ) + 'ms ' + ( animation.easing || 'linear' ) : 'none'; + + $letter.css({ + '-webkit-transition' : transition, + '-moz-transition' : transition, + '-o-transition' : transition, + '-ms-transition' : transition, + 'transition' : transition + }) + .css({ + '-webkit-transform' : transformation, + '-moz-transform' : transformation, + '-o-transform' : transformation, + '-ms-transform' : transformation, + 'transform' : transformation + }); + + }); + + }, + _loadEvents : function() { + + if( this.options.fitText ) { + + var _self = this; + + $(window).on( 'resize.arctext', function() { + + _self._calc(); + + // apply transformation. + _self._rotateWord(); + + }); + + } + + }, + set : function( opts ) { + + if( !opts.radius && + !opts.dir && + opts.rotate === 'undefined' ) { + return false; + } + + this.options.radius = opts.radius || this.options.radius; + this.options.dir = opts.dir || this.options.dir; + + if( opts.rotate !== undefined ) { + this.options.rotate = opts.rotate; + } + + this._calc(); + + this._rotateWord( opts.animation ); + + }, + destroy : function() { + + this.options.radius = -1; + this._rotateWord(); + this.$letters.removeData('x y a center'); + this.$el.removeData('arctext'); + $(window).off('.arctext'); + + } + }; + + var logError = function( message ) { + if ( this.console ) { + console.error( message ); + } + }; + + $.fn.arctext = function( options ) { + + if ( typeof options === 'string' ) { + + var args = Array.prototype.slice.call( arguments, 1 ); + + this.each(function() { + + var instance = $.data( this, 'arctext' ); + + if ( !instance ) { + logError( "cannot call methods on arctext prior to initialization; " + + "attempted to call method '" + options + "'" ); + return; + } + + if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) { + logError( "no such method '" + options + "' for arctext instance" ); + return; + } + + instance[ options ].apply( instance, args ); + + }); + + } + else { + + this.each(function() { + + var instance = $.data( this, 'arctext' ); + if ( !instance ) { + $.data( this, 'arctext', new $.Arctext( options, this ) ); + } + }); + + } + + return this; + + }; + +})( jQuery ); \ No newline at end of file