arctext.js实现文字平滑弯曲弧形效果的插件


Posted in Javascript onMay 13, 2019

本文介绍了实现文字平滑弯曲弧形效果的插件-arctext.js,分享给大家,具体如下:

arctext.js实现文字平滑弯曲弧形效果的插件

扇形的文字

有时候产品大佬就是很任性,说做一个宣传页,一个类似拱门的效果,每次文字不一样,但是文字得呈现拱形状,类似上图啦。

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

它能够自动计算每个文字正确的旋转角度,并且生成对应的CSS ,其实就是基于css3和jquery,使用起来也很方便。

1.创建一个容器装文字

<h3 id="title">文字弯曲效果类似扇形拱桥状</h3>

2.引入jquery和arctext.js

<script type="text/javascript" src="//code.jquery.com/jquery-1.8.2.min.js" ></script>
<script src="jquery.arctext.js"></script>

3.调用arctext的方法:

$(function(){
    $("#title").show().arctext({
      radius:180
    })
  })

arctext参数说明:

  • radius:弯曲度数,最小的值是文字长度,如果设置为-1,则显示直线。
  • rotate:默认true,为false则不旋转文字
  • dir:默认1 (1:向下弯曲 非1(-1,0,2等):向上弯曲 )
  • fitText:默认false,如果你想尝试使用fitText插件,设置为true,记住包装的标签需要fluid布局。

效果图完整demo:

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
   #title{
      font-size: 20px;
      color: #ffe400;
      text-align: center;
    }
  </style>
</head>
<body>
  <h3 id="title">文字弯曲效果类似扇形拱桥状</h3>
<script type="text/javascript" src="//code.jquery.com/jquery-1.8.2.min.js" ></script>
<script src="jquery.arctext.js"></script>
<script>
  $(function(){
    $("#title").arctext({
      radius:180
    })
  })
</script>
</body>
</html>

jquery.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 );

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
拖动Html元素集合 Drag and Drop any item
Dec 22 Javascript
javascript中的有名函数和无名函数
Oct 17 Javascript
JavaScript中奇葩的假值示例应用
Mar 11 Javascript
简单总结JavaScript中的String字符串类型
May 26 Javascript
BootStrap 超链接变按钮的实现方法
Sep 25 Javascript
JavaScript中${pageContext.request.contextPath}取值问题及解决方案
Dec 08 Javascript
js实现tab切换效果
Feb 16 Javascript
JavaScript实现经纬度转换成地址功能
Mar 28 Javascript
BootStrap自定义popover,点击区域隐藏功能的实现
Jan 23 Javascript
微信小程序提取公用函数到util.js及使用方法示例
Jan 10 Javascript
微信小程序 checkbox使用实例解析
Sep 09 Javascript
JS运算符优先级与表达式示例详解
Sep 04 Javascript
vue项目前端知识点整理【收藏】
May 13 #Javascript
使用jQuery如何写一个含验证码的登录界面
May 13 #jQuery
JQuery特殊效果和链式调用操作示例
May 13 #jQuery
JQuery的加载和选择器用法简单示例
May 13 #jQuery
koa+mongoose实现简单增删改查接口的示例代码
May 13 #Javascript
如何利用vue+vue-router+elementUI实现简易通讯录
May 13 #Javascript
vue百度地图 + 定位的详解
May 13 #Javascript
You might like
第十二节 类的自动加载 [12]
2006/10/09 PHP
php编写的一个E-mail验证类
2015/03/25 PHP
Ubuntu server 11.04安装memcache及php使用memcache来存储session的方法
2016/05/31 PHP
php实现留言板功能(会话控制)
2017/05/23 PHP
php实现session共享的实例方法
2019/09/19 PHP
laravel使用数据库测试注意事项
2020/04/10 PHP
在网站上应该用的30个jQuery插件整理
2011/11/03 Javascript
jQuery1.6 使用方法一
2011/11/23 Javascript
node.js操作mongoDB数据库示例分享
2014/11/26 Javascript
零基础搭建Node.js、Express、Ejs、Mongodb服务器及应用开发入门
2014/12/20 Javascript
为什么JS中eval处理JSON数据要加括号
2015/04/13 Javascript
JavaScript实现获得所有兄弟节点的方法
2015/07/23 Javascript
Bootstrap基本插件学习笔记之折叠(22)
2016/12/08 Javascript
Vue.js实现图片的随意拖动方法
2018/03/08 Javascript
jquery的 filter()方法使用教程
2018/03/22 jQuery
js jquery 获取某一元素到浏览器顶端的距离实现方法
2018/09/05 jQuery
解决angularJS中input标签的ng-change事件无效问题
2018/09/13 Javascript
JS实现点击生成UUID的方法完整实例【基于jQuery】
2019/06/12 jQuery
vue中js判断长时间不操作界面自动退出登录(推荐)
2020/01/22 Javascript
vue 解决provide和inject响应的问题
2020/11/12 Javascript
Python的时间模块datetime详解
2017/04/17 Python
python使用turtle库绘制时钟
2020/03/25 Python
用Python逐行分析文件方法
2019/01/28 Python
执行Django数据迁移时报 1091错误及解决方法
2019/10/14 Python
python list数据等间隔抽取并新建list存储的例子
2019/11/27 Python
使用python turtle画高达
2020/01/19 Python
python GUI库图形界面开发之PyQt5访问系统剪切板QClipboard类详细使用方法与实例
2020/02/27 Python
python 爬取腾讯视频评论的实现步骤
2021/02/18 Python
施华洛世奇西班牙官网:SWAROVSKI西班牙
2019/06/06 全球购物
JAVA程序员面试题
2012/10/03 面试题
施工安全协议书
2013/12/11 职场文书
区域销售主管岗位职责
2014/06/15 职场文书
2014年卫生工作总结
2014/11/27 职场文书
电信营业员岗位职责
2015/04/14 职场文书
好段摘抄大全(48句)
2019/08/08 职场文书
Vue项目打包、合并及压缩优化网页响应速度
2021/07/07 Vue.js