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>

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM