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 相关文章推荐
js对象数组按属性快速排序
Jan 31 Javascript
js获取input标签的输入值实现代码
Aug 05 Javascript
让新消息在网页标题闪烁提示的jQuery代码
Nov 04 Javascript
js实现拖拽效果(构造函数)
Dec 14 Javascript
BootStrap中按钮点击后被禁用按钮的最佳实现方法
Sep 23 Javascript
微信小程序 解决swiper不显示图片的方法
Jan 04 Javascript
基于Bootstrap的网页设计实例
Mar 01 Javascript
Angular 通过注入 $location 获取与修改当前页面URL的实例
May 31 Javascript
jQuery实现IE输入框完成placeholder标签功能的方法
Sep 20 jQuery
Vue data的数据响应式到底是如何实现的
Feb 11 Javascript
JS倒计时两种实现方式代码实例
Jul 27 Javascript
vue 实现锚点功能操作
Aug 10 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
《超神学院》霸气归来, 天使彦上演维多利亚的秘密
2020/03/02 国漫
无限级别菜单的实现
2006/10/09 PHP
PHP中使用crypt()实现用户身份验证的代码
2012/09/05 PHP
深入file_get_contents与curl函数的详解
2013/06/25 PHP
学习php过程中的一些注意点的总结
2013/10/25 PHP
Laravel 5框架学习之数据库迁移(Migrations)
2015/04/08 PHP
基于PHP+jQuery+MySql实现红蓝(顶踩)投票代码
2015/08/25 PHP
php官方微信接口大全(微信支付、微信红包、微信摇一摇、微信小店)
2015/12/21 PHP
PHP中PDO连接数据库中各种DNS设置方法小结
2016/05/13 PHP
onkeyup,onkeydown和onkeypress的区别介绍
2013/10/21 Javascript
Jquery ajax执行顺序 返回自定义错误信息(实例讲解)
2013/11/06 Javascript
js解决弹窗问题实现班级跳转DIV示例
2014/01/06 Javascript
修复bash漏洞的shell脚本分享
2014/12/31 Javascript
js中获取时间new Date()的全面介绍
2016/06/20 Javascript
bootstrap提示标签、提示框实现代码
2016/12/28 Javascript
js实现拖拽功能
2017/03/01 Javascript
vue实现表格数据的增删改查
2017/07/10 Javascript
JS数组操作之增删改查的简单实现
2017/08/21 Javascript
浅谈JavaScript find 方法不支持IE的问题
2017/09/28 Javascript
Vue 中使用vue2-highcharts实现曲线数据展示的方法
2018/03/05 Javascript
Python内置函数——__import__ 的使用方法
2017/11/24 Python
Python图像处理之图像的读取、显示与保存操作【测试可用】
2019/01/04 Python
python 获取等间隔的数组实例
2019/07/04 Python
Python Pandas中根据列的值选取多行数据
2019/07/08 Python
django 微信网页授权登陆的实现
2019/07/30 Python
将Python文件打包成.EXE可执行文件的方法
2019/08/11 Python
python_array[0][0]与array[0,0]的区别详解
2020/02/18 Python
Pandas数据分析的一些常用小技巧
2021/02/07 Python
htnl5利用svg页面高斯模糊的方法
2018/07/20 HTML / CSS
Ryderwear澳洲官网:澳大利亚高端健身训练装备品牌
2018/09/18 全球购物
写给女朋友的道歉信
2014/01/12 职场文书
销售员岗位职责
2015/02/10 职场文书
党员“一帮一”活动总结
2015/05/07 职场文书
朋友聚会开场白
2015/06/01 职场文书
大学开学典礼新闻稿
2015/07/17 职场文书
详解vue中v-for的key唯一性
2021/05/15 Vue.js