SVG之文本

一、文本标签<text>

  SVG支持直接对文本进行操作,如果我们需要在SVG中使用文本,那么我们需要使用到<text>标签。直接看一个简单的demo。

  •  1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4     <meta charset="utf-8">
     5     <title>textDemo</title>
     6 </head>
     7 <body>
     8     <svg id="svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="1000">
     9         <defs>
    10             <pattern id="grid" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
    11                 <path d="M0,0H20V20" style="stroke: #0006;fill: none"></path>
    12             </pattern>
    13         </defs>
    14         <!--网格背景-->
    15         <rect fill="url(#grid)" width="1400" height="1000"></rect>
    16         <!--文字-->
    17         <text x="100" y="100" fill="green" style="font-size: 50px;font-family: 'Arial';">你好,Hello SVG</text>
    18         <path d="M100,0V200M0,100H500" stroke="red" />
    19     </svg>
    20 </body>
    21 </html>

     这个demo中我们使用笔刷绘制了20*20大小的格子背景,方便观察坐标。我们发现属性:fill填充文字颜色;X,Y的值是文本的起始坐标(左下角坐标)。然而,汉字明显突出了界限,而英文字母则很好地位于Y值之上。

  除了X,Y属性,text还有两个重要的属性:

  • dx属性:横向位移字符。
  • dy属性:纵向位移字符。

  我们加入dx,dy属性来直接感受一下字符之间的变化(从第一个字符起生效):

  • <text x="100" y="100" fill="green" dx="10 20" dy="10 -10 10 -10 10 -10 10 -10 10 -10 10 -10" style="font-size: 50px;font-family: 'Arial';">你好,Hello SVG</text>

     一共有12个字符(包含空格),所以dx,dy应当有分别是12个数值,如果不足,默认为0。

二、<tspan>标签的使用

  1、小Demo

   <span>标签我们应该都很熟悉,对于内联元素我们一般使用<span>来处理。同样的,在SVG的<text>标签中,我们可以使用<tspan>标签进行内联元素处理。

  <tspan>的使用能更好地处理文本,特别是部分文本。比如上文的“你好,Hello SVG”,如果我们希望中文和英文的颜色不一样,那么我们可以使用<tspan>将文本“分割”来处理:

  • <text x="100" y="100">
        <tspan dx="10 10" dy="-10 20" fill="black" stroke="blue" style="font-size: 40px;">你好,</tspan>
        <tspan dx="0 0 0 0 0 0 10 -15 -15" dy="10 -10 10 -10 10 -10 10 -10 10" fill="none" stroke="green" style="font-size: 50px;font-family: 'Arial';">Hello SVG</tspan>
    </text>


    我们发现,dx和dy在<tspan>中由于字符串长度变短会变得更好调整。

  2、使用dx和dy属性:完成sin(x)文字动画

  利用dx和dy属性可以调整文本字符的横向和纵向位移距离,我们现在利用这个属性将26个字母按照y = A·sin(ax+b)这个函数进行排列。

  •  1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4     <meta charset="utf-8">
     5     <title>textDemo</title>
     6 </head>
     7 <body>
     8     <svg id="svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="1000">
     9         <defs>
    10             <pattern id="grid" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
    11                 <path d="M0,0H20V20" style="stroke: #0006;fill: none"></path>
    12             </pattern>
    13         </defs>
    14         <!--网格背景-->
    15         <rect fill="url(#grid)" width="1400" height="1000"></rect>
    16         <!--文字-->
    17         <text id="sinText" x="100" y="200" style="font-size: 18px;font-family: 'Arial';">ABCDEFGHIJKLMNOPQRSTUVWXYZ</text>
    18         <path d="M100,0V200M0,100H200" transform="translate(20,100)" stroke="red" />
    19     </svg>
    20     <script>
    21         //x = [20,20,20,...]
    22         //y = s*sin(w*x+t);
    23         var n = 26;
    24         var x = [];
    25         var y = null;
    26         var i = n;
    27         var s = 100;
    28         var w = 0.02;
    29         var t = 0;
    30 
    31         //横向间隔20
    32         while(i--) x.push(20);
    33         
    34         //纵向按照sin()函数变化
    35         function arrange(t){
    36             y = [];
    37             var ly = 0,cy;
    38             for(i=0;i<n;++i){
    39                 cy = -s* Math.sin(w * i * 20 +t);
    40                 y.push(cy - ly);
    41                 ly = cy;
    42             }
    43         }
    44         //将数组转换成字符串并设置为dx,dy值
    45         function render(){
    46             sinText.setAttribute('dx',x.join(' '));
    47             sinText.setAttribute('dy',y.join(' '));
    48         }
    49 
    50         //执行
    51         arrange(t);
    52         render();
    53         
    54     </script>
    55 </body>
    56 </html>

  

  • 现在我们可以动态改变设置t的值,使得这些文本动起来,我们只需要将arrange(t); render();两个方法替换为以下动态方法即可:
    //动态改变t的值
    function frame() {
        t += 0.02;
        arrange(t);
        render();
        window.requestAnimationFrame(frame);//动画效果:递归调用frame方法
    }
    frame();

  

  我们还可以稍加修饰,为每个字母即每个<tspan>增加fill属性,依次来渲染字母的颜色,我们只需要修改while()循环部分:

  • while(i--){
        x.push(20);
    
        var tspan = document.createElementNS(NS,'tspan');
        tspan.textContent = text[n - i - 1];
        sinText.appendChild(tspan);
        var h = Math.round(360/26 * i);//将颜色均分显示
        tspan.setAttribute('fill','hsl('+ h +',100%,50%)');
    }

  

三、文字的水平/垂直居中

  • 水平居中使用text-anchor属性,值包括:start、middle、end
  • 垂直居中使用dominant-baseline属性

  下面是一个演示器:

  •  1 <html>
     2     <head>
     3         <meta charset="utf-8">
     4         <title>SVG文本对齐</title>
     5     </head>
     6     <body>
     7         <br>
     8         <label>水平居中属性:text-anchor=</label>
     9         <select id="ta">
    10             <option value="start">start</option>
    11             <option value="middle">middle</option>
    12             <option value="end">end</option>
    13         </select>
    14         <span>------</span>
    15         <label>垂直居中属性:dominant-baseline=</label>
    16         <select id="select"></select>
    17         <br>
    18         <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="300">
    19             <path stroke="green" d="M0,100 h400 M140,0 v200" />
    20             <text id="text" x="140" y="100" fill="red" font-size="50">SVG</text>
    21             <rect id="rect" stroke="blue" fill="none"></rect>
    22         </svg>
    23 
    24         <script>
    25         var values = "auto | use-script | no-change | reset-size | ideographic | alphabetic | hanging | mathematical | central | middle | text-after-edge | text-before-edge | text-top | text-bottom".split(' | ');
    26     
    27         values.forEach(function(value) {
    28             var opt = document.createElement('option');
    29             opt.value = opt.textContent = value;
    30             select.appendChild(opt);
    31         });
    32     
    33         select.addEventListener('input', function() {
    34             text.setAttribute('dominant-baseline', select.value);
    35             var box = text.getBBox();
    36             rect.setAttribute('x', box.x);
    37             rect.setAttribute('y', box.y);
    38             rect.setAttribute('width', box.width);
    39             rect.setAttribute('height', box.height);
    40         });
    41     
    42         ta.addEventListener('input', function() {
    43             text.setAttribute('text-anchor', ta.value);
    44         });
    45         </script>
    46     </body>
    47 </html>

     

四、控制文本路径的标签<textpath>

  1、小栗子

   上面我们使用dx和dy属性对26个字母实现了文本按照sin()函数排列,但这并不是真正地按照路径排列。如果想要文本按照某个路径排列,我们需要使用<textPath>标签。直接看一个简单的栗子:

  •  1 <html>
     2 <head>
     3     <meta charset="utf-8">
     4     <title>路径文本</title>
     5 </head>
     6 
     7 <body>
     8     <svg xmlns="http://www.w3.org/2000/svg" width="800" height="600">
     9         <path id="path1" d="M 100 200 Q 200 100 300 200 T 500 200" stroke="green" stroke-width="2" fill="none" />
    10         <g fill="red">
    11             <circle cx="100" cy="200" r="4" />
    12             <circle cx="300" cy="200" r="4" />
    13             <circle cx="500" cy="200" r="4" />
    14         </g>
    15         <text style="font-size: 22px;">
    16             <textpath xlink:href="#path1">投我以木瓜,报之以琼琚,匪报也,永以为好也。</textpath>
    17         </text>
    18     </svg>
    19 </body>
    20 </html>

  其中,我们先使用<path>定义了一条路径,然后使用<textpath>来处理文本,并设置 xlink:href 参数来控制文本路径。

  2、一个演示器

  当我们使用<textpath>标签控制文本路径后,<text>的属性:x,y,dx,dy,会产生不一样的效果,下面是一个演示器,我们可以更直观的感受这种变化:

  •  1 <html>    
     2     <head>
     3         <meta charset="utf-8">
     4         <title>路径文本</title>
     5     </head>
     6     
     7     <body>
     8         <br>
     9         <form id="ctrl">
    10             <label>x:</label>
    11             <input id="x" ctrl="x" type="range" value="0" min="-200" max="200" />
    12             <label id="x_value" style="color: red">0</label>
    13             &nbsp;&nbsp;&nbsp;
    14             <label>text-anchor:</label>
    15             <select ctrl="text-anchor">
    16                 <option value="start" selected>start</option>
    17                 <option value="middle">middle</option>
    18                 <option value="end">end</option>
    19             </select>
    20             <br><br>
    21             <label>y:</label>
    22             <input id="y" ctrl="y" type="range" value="0" min="-200" max="200" />
    23             <label id="y_value" style="color: red">0</label>
    24             &nbsp;&nbsp;&nbsp;
    25 
    26             <label>startOffset:</label>
    27             <input id="startOffset" ctrl="startOffset" type="range" value="0" min="-100" max="100" />
    28             <label id="so_value" style="color: red">0</label>
    29 
    30             <br><br>
    31             <button type="reset" style="margin-left: 200px;">重置</button>
    32         </form>
    33         <svg xmlns="http://www.w3.org/2000/svg" width="800" height="600">
    34             <path id="path1" d="M 100 200 Q 200 100 300 200 T 500 200" stroke="green" fill="none" />
    35             <g fill="red">
    36                 <circle cx="100" cy="200" r="4" />
    37                 <circle cx="300" cy="200" r="4" />
    38                 <circle cx="500" cy="200" r="4" />
    39             </g>
    40             <text style="font-size: 20px;">
    41                 <textpath xlink:href="#path1">投我以木瓜,报之以琼琚,匪报也,永以为好也。</textpath>
    42             </text>
    43         </svg>
    44     </body>
    45     <script>
    46         // jshint browser: true
    47         var ctrl= document.getElementById('ctrl');
    48         var text = document.querySelector('text');
    49         var textPath = text.firstElementChild;
    50     
    51         function update(target) {
    52             var attr = target.getAttribute('ctrl');
    53             if(!attr) return;
    54             if(attr == 'startOffset') {
    55                 textPath.setAttribute(attr, target.value + '%');
    56             } else {
    57                 text.setAttribute(attr, target.value);
    58             }
    59         }
    60 
    61         function info(){
    62             var x_value = document.getElementById('x_value');
    63             var y_value = document.getElementById('y_value');
    64             var so_value = document.getElementById('so_value');
    65             x_value.innerText = x.value;
    66             y_value.innerText = y.value;
    67             so_value.innerText = startOffset.value;
    68         }
    69 
    70         ctrl.addEventListener('input', function(e){
    71             update(e.target);
    72             info();
    73         })
    74     
    75         ctrl.addEventListener('reset', function(){
    76             setTimeout(function(){
    77                 var list = document.querySelectorAll('#ctrl *[ctrl]');
    78                 [].slice.call(list).forEach(update);
    79                 info();
    80             })
    81         })
    82     </script>
    83 </html>

  

  这里面startOffset的值决定了其实文本偏移位置,和之前的text-anchor类似。上面没有将dx,dy属性添加进去,但是也会影响文本路径。

五、超链接<a>标签的使用

  <a>标签我们都很熟悉,嗯?在SVG中同样提供了同名的<a>标签,可以作为任意图形的超链接。

  • xlink:href属性:规定连接URL。
  • xlink:title属性:显示连接提示信息。
  • target属性:指定在何处打开目标。可选值如下:

  下面是一个简单的实例:

  •  1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4     <meta charset="utf-8">
     5     <title>SVG超连接</title>
     6 </head>
     7 <body>
     8     <svg xmlns="http://www.w3.org/2000/svg">
     9         <a xlink:href="http://www.cnblogs.com/fzz9" xlink:title="博客园_fzz" target="_blank">
    10             <rect height="30" width="100" y="0" x="0" rx="15"></rect>
    11             <text fill="white" text-anchor="middle" y="21" x="45">
    12                 <tspan id="feng" style="font-size: 30px;font-family:STXinwei;"></tspan>
    13                 <tspan>之之</tspan>
    14             </text>
    15         </a>
    16     </svg>
    17     <script type="text/javascript">
    18         var h = 0;
    19 
    20         //动态设置字体颜色
    21         function setColor(h){
    22             var feng = document.getElementById('feng');
    23             feng.setAttribute('stroke','hsl('+ h +',100%,50%)');
    24         }
    25         function frame(){
    26             setColor(h);
    27             h += 0.8;
    28             if(h>=360) h = 0;
    29             window.requestAnimationFrame(frame);//动画效果:递归调用frame方法
    30         }
    31         frame();
    32     </script>
    33 </body>
    34 </html>

  

posted @ 2018-07-03 15:24  风之之  阅读(4851)  评论(0编辑  收藏  举报