尝试自己使用canvas画和css3的rotate旋转div,两种方法都是计算旋转角度的时候很麻烦,因为可能5个字10个字,但是得均匀地呈拱形分布,要知道让每个文字都沿着弯曲路径排布相当的复杂,于是便发现了这个好用的插件---arctext.js
- /**
- * 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 );