俗話說得好:最好的學習方法是興趣引導的學習,在學習SVG以前,先給大家看看一些實例,讓大家領略一下SVG的強大,看看能不能激發出大家的學習興趣。 https://www.html5tricks.com/tag/svg/
感受怎麼樣呢?是否是很是想學習SVG,作一個屬於本身的做品出來啊?那就開始學習吧。javascript
目錄css
SVG入門html
SVG簡介html5
位圖和矢量圖java
使用方式git
SVG的圖形和基本屬性github
基本圖形canvas
基本屬性瀏覽器
基本操做APIapp
SVG入門
SVG簡介
使用XML描述的矢量文件
位圖和矢量圖
位圖:基於顏色的描述(BMP、PNG、JPG等),圖片是像素型,清晰度較低
矢量圖:基於數學的描述(SVG、AI等),圖片曲線圓滑,清晰度較高
使用方式
瀏覽器直接打開
SVG矢量圖文件後綴爲 .svg
在HTML中使用<img>標籤引用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>在HTML中使用img引用</title> </head> <body> <p><img src="SVG.svg">原始大小</p> <p><img src="SVG.svg" width="50" height="50">50 X 50</p> //可直接設置大小 <p><img src="SVG.svg" width="400" height="400">400 X 400</p> </body> </html>
可愛又機智的笑臉
直接在HTML中使用SVG標籤
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>smile-SVG</title> </head> <body> <p> <svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"> <!--Face--> <circle cx="100" cy="100" r="90" fill="#39F"/> <!--Eyes--> <circle cx="70" cy="80" r="20" fill="white"/> <circle cx="130" cy="80" r="20" fill="white"/> <circle cx="65" cy="75" r="10" fill="black"/> <circle cx="125" cy="75" r="10" fill="black"/> <!--Smile--> <path d="M 50 140 A 60 60 0 0 0 150 140" stroke="white" stroke-width="3" fill="none"/> </svg> </p> </body> </html>
做爲CSS背景
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>在css使用SVG</title> <style> body{ background-color: #efefef; } #bg{ width: 400px; height: 400px; background: white url("SVG.svg") repeat; box-shadow:rgba(0,0,0,.5) 2px 3px 10px; border-radius: 10px; } </style> </head> <body> <h1>Hello SVG with CSS</h1> <div id="bg"></div> </body> </html>
SVG的圖形和基本屬性
基本圖形
<rect> 矩形
x y 橫座標和縱座標(矩形左上角的位置)
width 寬
height 高
rx ry 圓角大小 (只設置rx或ry,則二者的值相同,只有分別設置了不一樣的值纔會各自顯示不一樣的大小)
<circle>圓形
cx cy 橫座標和縱座標(圓形的中心點)
r 半徑
<ellipse>橢圓
cx cy 橫座標和縱座標
rx ry 橫向半徑和縱向半徑
<line> 線段
x1 y1 端點座標
x2 y2 端點座標
<polyline>折線
points="x1 y1 x2 y2 x3 y3.."
多少個節點就設置多少個x y 值
.
<polygon>多邊形
points="x1 y1 x2 y2 x3 y3.."
多少個節點就設置多少個x y 值,第一個節點和最後一個節點會自動鏈接在一塊兒
基本屬性
fill = 「#FFB3AE」 填充顏色
stroke = #971817 描邊顏色
stroke-width = 10 描邊的粗細
transform = "rotate(30)" 旋轉變形
基本操做API
建立圖形
document.createElementNS(ns, tagName)
ns是必須設置的,由於svg是單獨的xml文件,在html中沒有svg的命名空間。tagName指的是基本圖形cicle line等
添加圖形
element.appendChild(childElement)
設置/獲取屬性:
element.setAttribute(name, value)
element.getAttribute(name)
經過以上屬性製做的svgEditor
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>SVG 編輯器</title> <style> #toolbox { position: absolute; top: 0; bottom: 0; left: 0; width: 250px; border-right: 1px solid #CCC; } #toolbox h2 { margin: 0; padding: 0; background: #EEE; font-size: 16px; height: 24px; line-height: 24px; padding: 5px 10px; } #toolbox form { padding: 10px; } #canvas { position: absolute; left: 260px; top: 10px; bottom: 10px; right: 10px; box-shadow: 2px 2px 10px rgba(0,0,0,.4); border-radius: 5px; } label { display: inline-block; width: 80px; text-align: right; } </style> </head> <body> <div id="toolbox"> <h2>建立</h2> <form id="create-shape"> <button type="button" create="rect">Rect</button> <button type="button" create="circle">Circle</button> <button type="button" create="ellipse">Ellipse</button> <button type="button" create="line">Line</button> </form> <h2>形狀</h2> <form id="shape-attrs"> 請先建立圖形 </form> <h2>外觀和變換</h2> <form id="look-and-transform" disabled="disabled"> <p> <label style="display: inline;">填充</label> <input id="fill" type="color" value="#ffffff" /> </p> <p> <label style="display: inline;">描邊</label> <input id="stroke" type="color" value="#ff0000" /> <input id="strokeWidth" type="range" value="1" /> </p> <p> <label>translateX</label> <input id="translateX" type="range" min="-400" max="400" value="0" /> <label>translateY</label> <input id="translateY" type="range" min="-400" max="400" value="0" /> <label>rotate</label> <input id="rotate" type="range" min="-180" max="180" value="0" /> <label>scale</label> <input id="scale" type="range" min="-1" max="2" step="0.01" value="1" /> </p> </form> </div> <div id="canvas"></div> </body> <script> var SVG_NS = 'http://www.w3.org/2000/svg'; // 圖形及對應默認屬性 var shapeInfo = { rect: 'x:10,y:10,width:200,height:100,rx:0,ry:0', circle: 'cx:200,cy:200,r:50', ellipse: 'cx:200,cy:200,rx:80,ry:30', line: 'x1:10,y1:10,x2:100,y2:100' }; // 默認公共屬性 var defaultAttrs = { fill: '#ffffff', stroke: '#ff0000' }; var createForm = document.getElementById('create-shape'); var attrForm = document.getElementById('shape-attrs'); var lookForm = document.getElementById('look-and-transform'); var svg = createSVG(); var selected = null; createForm.addEventListener('click', function(e) { if (e.target.tagName.toLowerCase() == 'button') { create(e.target.getAttribute('create')); } }); attrForm.addEventListener('input', function(e) { if (e.target.tagName.toLowerCase() != 'input') return; var handle = e.target; selected.setAttribute(handle.name, handle.value); }); lookForm.addEventListener('input', function(e) { if (e.target.tagName.toLowerCase() != 'input') return; if (!selected) return; selected.setAttribute('fill', fill.value); selected.setAttribute('stroke', stroke.value); selected.setAttribute('stroke-width', strokeWidth.value); selected.setAttribute('transform', encodeTranform({ tx: translateX.value, ty: translateY.value, scale: scale.value, rotate: rotate.value })); }); function createSVG() { var svg = document.createElementNS(SVG_NS, 'svg'); svg.setAttribute('width', '100%'); svg.setAttribute('height', '100%'); canvas.appendChild(svg); svg.addEventListener('click', function(e) { if (e.target.tagName.toLowerCase() in shapeInfo) { select(e.target); } }); return svg; } function create(name) { var shape = document.createElementNS(SVG_NS, name); svg.appendChild(shape); select(shape); } function select(shape) { var attrs = shapeInfo[shape.tagName].split(','); var attr, name, value; attrForm.innerHTML = ""; while(attrs.length) { attr = attrs.shift().split(':'); name = attr[0]; value = shape.getAttribute(name) || attr[1]; createHandle(shape, name, value); shape.setAttribute(name, value); } for (name in defaultAttrs) { value = shape.getAttribute(name) || defaultAttrs[name]; shape.setAttribute(name, value); } selected = shape; updateLookHandle(); } function createHandle(shape, name, value) { var label = document.createElement('label'); label.textContent = name; var handle = document.createElement('input'); handle.setAttribute('name', name); handle.setAttribute('type', 'range'); handle.setAttribute('value', value); handle.setAttribute('min', 0); handle.setAttribute('max', 800); attrForm.appendChild(label); attrForm.appendChild(handle); } function updateLookHandle() { fill.value = selected.getAttribute('fill'); stroke.value = selected.getAttribute('stroke'); var t = decodeTransform(selected.getAttribute('transform')); translateX.value = t ? t.tx : 0; translateY.value = t ? t.ty : 0; rotate.value = t ? t.rotate : 0; scale.value = t ? t.scale : 1; } function decodeTransform(transString) { var match = /translate\((\d+),(\d+)\)\srotate\((\d+)\)\sscale\((\d+)\)/.exec(transString); return match ? { tx: +match[1], ty: +match[2], rotate: +match[3], scale: +match[4] } : null; } function encodeTranform(transObject) { return ['translate(', transObject.tx, ',', transObject.ty, ') ', 'rotate(', transObject.rotate, ') ', 'scale(', transObject.scale, ')'].join(''); } </script> </html>
SVG的座標系統和座標變換
SVG的世界、視野、視窗概念
視野(viewBox)是觀察世界的一個矩形區域(坐井觀天中,井口就是你的視野)
視窗 是瀏覽器開闢出來的用於渲染SVG的區域
preserveAspectRatio-控制視野(視野和視窗不一致的狀況使用)
世界 是SVG定義的,無窮大的
下面是我對三者關係畫的圖,但願幫助你們理解。
對視野、視窗、還有preserveAspectRatio的屬性的使用作出來的實例,你們可在瀏覽器打開操做一下。
<!DOCTYPE html> <html> <head> <title>ViewBox 使用演示</title> <style> body { background: #eee; } svg { position: absolute; border: 1px solid green; width: 300px; height: 200px; left: 50%; top: 50%; margin-top: -100px; margin-left: -150px; background: white; } input[type=number] { width: 50px; } </style> </head> <body> <h1>ViewBox 演示</h1> <form id="form"> <fieldset> <legend>viewBox</legend> <label>x: <input id="vx" type="number" value="0"></label> <label>y: <input id="vy" type="number" value="0"></label> <label>width: <input id="vw" type="number" value="300"></label> <label>height: <input id="vh" type="number" value="200"></label> </fieldset> <fieldset> <legend>preserveAspectRatio</legend> <label>align: <select id="align"> <option value="none">none</option> <option value="xMinYMin">xMinYMin</option> <option value="xMidYMin">xMidYMin</option> <option value="xMaxYMin">xMaxYMin</option> <option value="xMinYMid">xMinYMid</option> <option value="xMidYMid" selected>xMidYMid</option> <option value="xMaxYMid">xMaxYMid</option> <option value="xMinYMax">xMinYMax</option> <option value="xMidYMax">xMidYMax</option> <option value="xMaxYMax">xMaxYMax</option> </select></label> <label>meetOrSlice: <select id="meetOrSlice"> <option value="meet">meet</option> <option value="slice">slice</option> </select></label> </fieldset> </form> <p> <svg id="svg" xmlns="http://www.w3.org/2000/svg"> <!--Face--> <circle cx="100" cy="100" r="90" fill="#39F" /> <!--Eyes--> <circle cx="70" cy="80" r="20" fill="white" /> <circle cx="130" cy="80" r="20" fill="white" /> <circle cx="65" cy="75" r="10" fill="black" /> <circle cx="125" cy="75" r="10" fill="black"/> <!--Smile--> <path d="M 50 140 A 60 60 0 0 0 150 140" stroke="white" stroke-width="3" fill="none" /> <rect id="viewBoxIndicator" stroke="red" stroke-width="3.5" fill="none" /> </svg> </p> <script> function update() { var viewBox = [vx.value, vy.value, vw.value, vh.value].join(' '); var preserveAspectRatio = [align.value, meetOrSlice.value].join(' '); svg.setAttribute('viewBox', viewBox); svg.setAttribute('preserveAspectRatio', preserveAspectRatio); var rect = viewBoxIndicator; rect.setAttribute('x', vx.value); rect.setAttribute('y', vy.value); rect.setAttribute('width', vw.value); rect.setAttribute('height', vh.value); } form.addEventListener('input', update); update(); </script> </body> </html>
SVG中的圖形分組
<g>標籤來建立分組
一種總體思惟,對多個事物合成分組,而後總體設置其屬性
屬性繼承
transfrom屬性定義座標變換
能夠嵌套使用
座標系統概述
笛卡爾直接座標系
原點
互相垂直的兩條數軸
角度定義:正反向是指順時針方向
四個座標系
用戶座標系(User Coordinate):世界的座標系,SVG原始座標系,其餘座標系都是從用戶座標系產生的
自身座標系(Current Coordinate):每一個圖形元素或分組獨立與生俱來的
前驅座標系(Previous Coordinate):父容器的座標系
參考座標系(Reference Coordinate):使用其餘座標系來考究自身的狀況時使用的,經常使用於圖形之間的對齊
如下是對各類座標系之間的關係作的圖,但願有助於你們理解
座標變換
定義
數學上,是指採用必定的數學方法將一個座標系的座標變換成另外一個座標的座標的過程。
SVG中,是指自身座標系經過座標變換後獲得的新的自身座標系的描述。
transform屬性
定義前驅座標系到自身座標系的線性變換
語法:
rotate(<deg>) 定義元素的旋轉
translate(<x>,<y>) 定義元素的平移
scale(<sx>,<sy>) 定義元素的x方向和y方向縮放
matrix(<a>,<b>,<c>,<d>,<e>,<f>) 定義變化矩陣,其實以上三種語法的本質原理就是改變matrix的值實現的變換,只是上面的表達更容易讓人理解。
順便講一下matrix這個重點
矩陣的書寫
矩陣實現變換的原理
例:matrix(1, 0, 0, 1, 30, 30) //a=1, b=0, c=0, d=1, e=30, f=30
假設原中心點爲(0,0)即x=0,y=0, 則x的座標ax+cy+e=1*0+0*0+30 = 30 ; y的座標bx+dy+f=0*0+1*0+30 = 30
因此是原中心點變爲了(30,30),元素實現了平移,不知道這麼說你們對matrix會不會有必定的瞭解,若是還不懂則去百度一下吧
如下有一個關於transform的實例,你們能夠操做一下,加深對transform屬性的瞭解。
注:t 100 100 r30(先平移後旋轉) 和 r30 t 100 100 (先旋轉後平移)是不同的,你們能夠去操做理解一下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>transform屬性</title> <style media="screen"> svg{ background-color: #fcfcfc; display: block; margin: 20px auto; border: 1px solid #ccc; } #transform{ width: 300px; } </style> </head> <body> <fieldset> <legend>設置</legend> <label for="">分組: <select id="group"> <option value="a">a</option> <option value="b">┗b</option> <option value="c"> ┗c</option> <option value="d">┗d</option> </select> </label> <label for="">變換: <input type="text" id="tc" /> <span id="ts"></span> </label> <p> 分組:選擇相應的座標系進行變換<br> 變換:<br> 旋轉 r 100 <=> rotate(100)<br> 平移 t 100 100 <=> translate(100, 100)<br> 縮放 s 3 3 <=> scale(3, 3)<br> 集合 m a b c d e f <=> matrix(a, b, c, d, e, f) </p> </fieldset> <svg xmlns="http://www.w3.org/2000/svg" width="1000" height="600" viewBox="-200.5 -100.5 1000 600"> <defs> <g id="coord"> <line x1="0" y1="0" x2="300" y2="0"/> <line x1="0" y1="0" x2="0" y2="300"/> <circle cx="0" cy="0" r="2"/> <circle cx="100" cy="0" r="2"/> <circle cx="200" cy="0" r="2"/> <circle cx="0" cy="100" r="2"/> <circle cx="0" cy="200" r="2"/> </g> </defs> <use xlink:href="#coord" stroke="black" fill="black"/> <text fill="black" x="5" y="20">World</text> <g id="a" stroke="red" fill="red"> <use xlink:href="#coord"/> <text x="5" y="20">a</text> <g id="b" stroke="blue" fill="blue"> <use xlink:href="#coord"/> <text x="5" y="20">b</text> <g id="c" stroke="green" fill="green"> <use xlink:href="#coord"/> <text x="5" y="20">c</text> </g> </g> <g id="d" stroke="pink" fill="pink"> <use xlink:href="#coord"/> <text x="5" y="20">d</text> </g> </g> </svg> <script> function target() { return document.getElementById(group.value); } // 把變換命令轉換爲字符串 // 't 10 10 r 30 s 1.3' => 'translate(10, 10) rotate(30) scale(1.3)' function tc2ts(tc) { var arr = (tc || '').split(' '); var ts = ''; var elem, lastElemType; var cmd = { 't': 'translate(', 'r': 'rotate(', 's': 'scale(', 'm': 'matrix(' }; while ( elem=arr.shift() ) { if ( cmd[elem] ) { if ( lastElemType=='number' ) ts += ') '; ts += cmd[elem]; lastElemType = 'command'; } else { if ( lastElemType=='number' ) ts += ', '; ts += elem; lastElemType = 'number'; } } if ( ts.length ) ts += ')'; return ts; } group.oninput = function() { tc.value = target().tc || ''; ts.innerHTML = tc2ts(tc.value); }; tc.oninput = function() { target().tc = tc.value; target().setAttribute('transform', ts.innerHTML = tc2ts(tc.value)); }; </script> </body> </html>
SVG顏色、漸變和筆刷
RGB和HSL
RGB
紅色、綠色、藍色三個量值
表示方式有rgb(r, g, b) 或#rrggbb
每一個份量取值範圍:[0, 255]
優點:顯示器容易解析,故比較經常使用
劣勢:不符合人類描述顏色的習慣,修改顏色,暗度,亮度時須要改多個值。
HSL
顏色、飽和度、亮度三個份量
格式:hsl(h, s%, l%)
取值範圍:h:[0, 359] s,l: [0, 100]
優點:符合人類描述顏色的習慣,順便附上一個酷酷的hsl配色網站 http://paletton.com/
透明度
rgba(r, g, b, a) 和 hsla(h, s%, l%, a) 表示帶透明度的顏色
opacity屬性表示元素的透明度
a和opacity的取值範圍:[0, 1]
使用方法:
<rect fill="rgb(255,0,0)" opacity="0.5"/> <rect stroke="hsla(0, 50%, 60%, 0.5)"/>
線性漸變和徑向漸變
線性漸變
<linearGradient> 和 <stop>
定義方向
關鍵點位置及顏色
gradientUnits用兩個屬性:
objectBoundingBox 這是默認屬性,使用x1=0, y1=0, x2=1, y2=1分別表示圖形的最左端(0), 最上端(0), 最右端(1), 最低端 (1)
userSpaceOnUse 位置座標使用世界座標系,單位是px
註釋:如沒有設置gradientUnits屬性,則默認使用objectBoundingBox
使用方法:
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"> <defs> <!--objectBoundingBox屬性--> <linearGradient id="grad1" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="1"> <!--userSpaceOnUse屬性--> <!--<linearGradient id="grad1" gradientUnits="userSpaceOnUse"--> <!--x1="100" y1="100" x2="150" y2="150">--> <stop offset="0" stop-color="#1497FC"/> <stop offset="0.5" stop-color="#A469BE"/> <stop offset="1" stop-color="#FF8C00"/> </linearGradient> </defs> <rect x="100" y="100" fill="url(#grad1)" width="200" height="150"/> </svg>
徑向漸變
<radialGradient> 和 <stop>
定義方向
關鍵點位置及顏色 cx 和 cy
gradientUnits
焦點位置 fx 和 fy
實例:
<svg xmlns="http://www.w3.org/2000/svg"> <defs> <radialGradient id="grad2" cx="0.5" cy="0.5" r="0.5" fx="0.5" fy="0.5" > <stop offset="0" stop-color="rgb(20, 151, 252)"/> <stop offset="0.5" stop-color="rgb(164, 105, 190)"/> <stop offset="1" stop-color="rgb(255, 140, 0)"/> </radialGradient> </defs> <rect x="100" y="100" width="200" height="150" fill="url(#grad2)"></rect> </svg>
<stop>
定義漸變上的顏色坡度,能夠是<linearGradient>線性漸變或<radialGradient>徑向漸變的子元素
offset 定義顏色百分比,取值範圍:[0, 100%]
stop-color 定義漸變顏色
stop-opacity 定義漸變透明度
使用筆刷
繪製文理
<pattern>標籤
patternUnits 和 patternContentUnits
objectBoundingBox 這是默認屬性,使用x1=0, y1=0, x2=1, y2=1分別表示圖形的最左端(0), 最上端(0), 最右端(1),最低端 (1)
userSpaceOnUse 位置座標使用世界座標系,單位是px
<svg xmlns="http://www.w3.org/2000/svg"> <defs> <pattern id="grad2" x="0" y="0" width="0.25" height="0.25" patternUnits=" objectBoundingBox" patternContentUnits="objectBoundingBox"> <circle cx="0.1" cy="0.1" r="0.1" fill="red"></circle> </pattern> </defs> <rect x="100" y="100" width="800" height="300" fill="url(#grad2)" stroke="blue"></rect> </svg>
首先問你們一個問題,你以爲以上圖片是怎麼畫出來的?畫板繪製?no,手繪?no.這是用path工具畫出來的,怎麼樣?是否是瞬間以爲path很強大,那趕忙一塊兒學習吧。
path高級教程
Path概述
表示路徑,一個強大的繪圖工具
基本命令
M = moveto 移動當前位置
L = lineto 從當前位置繪製線段到指定位置
H = horizontal lineto 從當前位置繪製水平線到達指定地x座標
V = vertical lineto 從當前位置繪製豎直線到達指定地y座標
C = curveto 從當前位置繪製三次貝塞爾曲線到指定位置
S = smooth curveto 從當前位置光滑繪製三次貝塞爾曲線到指定位置
Q = quadratic Belzier curve 從當前位置繪製二次貝塞爾曲線到指定位置
T = smooth quadratic Belzier curveto 從當前位置光滑繪製二次貝塞爾曲線到指定位置
A = elliptical Arc 從當前位置繪製弧線到指定位置
Z = closepath 關閉路徑
註釋:
以上的翻譯不必定是正確的,最好是本身使用一下屬性而後理解一下它們的用處和原理
大寫表示座標參數爲絕對定位,小寫表示相對定位(相對上一次畫筆所在位置)。
最後參數表示最終要到達的位置
命令能夠重複參數表示重複執行同一條命令
例:複製一下文件,建立一個svg格式的文件,而後在瀏覽器中打開。
此例子定義了一條路徑,開始於位置250 150, 到達位置150 350,而後再到350 350, 最後在250 150 關閉路徑
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg"> <path d="M250 150 L150 350 L350 350 Z" /> </svg>
效果圖
移動和直線命令
M (x, y) + 移動畫筆,通常是設置畫筆開始位置,若是後面有重複參數則會當作L命令處理
L (x, y) + 繪製直線到指定位置
H (x) + 繪製水平線到指定的x位置
V (y) + 繪製豎直線到指定的y位置
若是使用小寫 m、l、h、v 則是使用相對位置繪製
注:使用絕對座標時,方便咱們對圖形總體(宏觀)的把握,而使用相對座標時,則有助於咱們對圖形的細節(微觀)的把握,因此,按具體狀況選擇合適的命令格式。
弧線命令
A(rx, ry, xr, laf, sf, x, y) ——繪製弧線
rx - (radius-x) 弧線所在橢圓的x半軸長
ry - (radius-y) 弧線所在橢圓的y半軸長
xr - (xAxis-rotation) 弧線所在橢圓的長軸角度
laf - (large-arc-flag) 是否選擇弧長較長的那一段弧 取值0(短弧) 或 1(長弧)
sf - (sweep-flag) 是否選擇逆時針方向的那一段弧 取值0(順時針) 或 1(逆時針)
x, y - 弧的終點位置
實例:
<svg xmlns="http://www.w3.org/2000/svg"> <path d="M 300 300 A 300 300 0 0 1 500 500" stroke="red" stroke-width="1" fill="none"/> </svg>
解釋:下圖可能畫得有點雜亂,但大家那麼強大,一眼就能看明白的。這是最爲簡單的一種畫法,能夠跟其餘命令混合使用,若是設計感強的,能夠利用這些命令製做出很精美的圖片。
效果圖
有興趣的能夠畫一下下面這張圖
貝塞爾曲線
SVG只能畫二次貝塞爾曲線和三次貝塞爾曲線:
二次貝塞爾曲線 P0和P2是起始結點和終結點,而P1是P0和P2以外的點。綠線是由P0到P1時的結點和P1到P2時的結點產生,曲線由起始結點畫線到終結點。
三次貝塞爾曲線 P0和P3是起始結點和終結點,而P1,P2是P0和P3以外的點。
二次貝塞爾曲線繪製命令
起始點
結束點
控制點
控制線
M x0 y0 Q x1 y1 x y
三次貝塞爾曲線繪製命令
M x0 y0 C x1 y1 x2 y2 x y
介紹一個牛人作的網站 http://myst729.github.io/bezier-curve/ 能夠在線看到貝塞爾曲線的畫線過程
光滑貝塞爾曲線
-T:Q的光滑版本
C1是上一段曲線的控制點關於當前曲線起始點的鏡像位置
-S:C的簡化版本
C1是上一段曲線的控制點2關於當前起始點的鏡像位置
SVG文本
<text> 和 <tspan> 建立文本
x和y屬性 - 定位標準
<svg xmlns="http://www.w3.org/2000/svg"> <text x="100" y="100" style="font-size:50px " >ABCDE</text> </svg>
dx和dy屬性 - 字形偏移
<svg xmlns="http://www.w3.org/2000/svg"> <text x="100" y="100" dx="20 20 20 20 20" dy="20 20 20 20 20" style="font-size:50px " >ABCDE</text> </svg>
style屬性 - 設置樣式
直接對text元素設置屬性
實例:如下一個動圖,可自行下載到html文件中,在瀏覽器打開。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>svg</title> </head> <body> <svg width="1200" height="1000" version="1.1" xmlns="http://www.w3.org/2000/svg"> <defs> <pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse"> <path d="M0,0H20V20" stroke-width="1" stroke="#f0f0f0" fill="none"/> </pattern> </defs> <rect x="0" y="0" width="1200" height="1000" fill="url(#grid)" stroke="" stroke-width=""/> <text x="100" y="150" font-size="14px" font-family="Microsoft YaHei">ABCDEFGHIJKLMNOPQRSTUVWXYZ</text> <path d="M100,0V200M0,100H200" stroke="red" fill="none" transform=translate(0,50) ></path> </svg> <script type="text/javascript"> var n = 26; var x = []; var y = null; var i = n; var s = 100; var w = 0.02; var t = 0.2; var sintext = document.getElementsByTagName('text')[0]; while(i--) x.push(20); function arrange(t) { y = []; var ly = 0; var cy; for(i=0;i<n;i++){ cy = -s * Math.sin(w * i * 20 + t); y.push(cy - ly); ly = cy; } } function render() { sintext.setAttribute("dx",x.join(' ')); sintext.setAttribute("dy",y.join(' ')); } function frame() { t += 0.01; arrange(t); render(); requestAnimationFrame(frame); } frame(); </script> </body> </html>
tspan爲文本添加樣式
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>svg</title> </head> <body> <svg width="1200" height="1000" version="1.1" xmlns="http://www.w3.org/2000/svg"> <defs> <pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse"> <path d="M0,0H20V20" stroke-width="1" stroke="#f0f0f0" fill="none"/> </pattern> </defs> <rect x="0" y="0" width="1200" height="1000" fill="url(#grid)" stroke="" stroke-width=""/> <text x="100" y="150" font-size="20px" font-family="Microsoft YaHei"></text> <path d="M100,0V200M0,100H200" stroke="red" fill="none" transform=translate(0,50) ></path> </svg> <script type="text/javascript"> var NS = 'http://www.w3.org/2000/svg'; var text = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; var n = text.length; var x = []; var y = null; var i = n; var s = 100; var w = 0.02; var t = 0.2; var sintext = document.getElementsByTagName('text')[0]; 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%, 80%)'); } function arrange(t) { y = []; var ly = 0; var cy; for(i=0;i<n;i++){ cy = -s * Math.sin(w * i * 20 + t); y.push(cy - ly); ly = cy; } } function render() { sintext.setAttribute("dx",x.join(' ')); sintext.setAttribute("dy",y.join(' ')); } function frame() { t += 0.01; arrange(t); render(); requestAnimationFrame(frame); } frame(); </script> </body> </html>
垂直居中問題
text-anchor - 水平居中屬性
dominant-baseline 屬性
<textPath>讓文本在制定路徑上排序
使用方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>textPath路徑文本</title> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" width="800" height="600"> <path id="path1" d="M 100 200 Q 200 100 300 200 T 500 200" stroke="rgb(0, 255, 0)" fill="none"/> <text style="font-size:14px;"> <textPath xlink:href="#path1"> 歡迎來到shareclub!!!歡迎來到shareclub!!!歡迎來到shareclub!!! </textPath> </text> </svg> </body> </html>
佈局原理
瀏覽器從字體表中查出此字體的寬度,而後在曲線中找到相同的寬度,而後找一箇中心點畫出垂直座標,而後把字體的基線對其到法線上。
最後一個點做爲第二個字的第一個起點,而後以相同原理對齊
定位屬性
x / dx:控制字體沿着曲線先後移動,超出曲線部分會被截取不顯示
y:y對於文本沒有任何做用
dy:在法線方向上下移動文本
text-anchor:
-start 以字符串開頭第一個字母爲焦點對齊
-middle 以字符串中間的字母爲焦點對齊
-end 以字符串最後一個字母爲焦點對齊
startOffset:設置起始點
腳本控制
setAttributeNS() 方法設置xlink:href屬性
把文本節點替換爲<textpath>節點
<a>插入超連接
能夠添加到任何的圖形上
xlink:href 指定鏈接地址
xlink:title 指定鏈接提示
target 指定打開目標
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>a超連接</title> </head> <body> <svg xmlns="http://www.w3.org/2000/svg"> <a xlink:href="http://www.baidu.com" xlink:title="百度" target="_blank"> <rect x="100" y="100" width="100" height="100" fill="rgba(255, 0, 0, 0.5" stroke="red" stroke-width="3"> </rect> </a> </svg> </body> </html>
圖形的引用、裁切和蒙版
<use>標籤建立圖形引用
實例:滿天星星
<clip> 標籤裁切圖形
實例:繪製燈塔的光線
<mask> 標籤建立蒙版
實例:繪製月牙及湖面倒影
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>starsky</title> <style> html,body{ margin:0; padding:0; width:100%; height:100%; background:#001122; line-height:0; font-size:0; } </style> </head> <body> <svg width="100%" height="100%" viewBox = "-400 -300 800 600" perserveAspectRatio="xMidYMid slice"> <!--星星繪畫:先畫出一個星星,而後使用use畫出一樣形狀,但不一樣大小的星星--> <defs> <polygon id="star" points="0 -10 2 -2 10 0 2 2 0 10 -2 2 -10 0 -2 -2" fill="white"></polygon> </defs> <!--真實事物-->、 <g id="real"> <!--星星--> <g id="star-group"></g> <!--使用group的好處:後期能夠隨之總體調整位置--> <!--月亮--> <g id="moon-group"> <mask id="moon-mask"> <!--月亮繪製:定義一個蒙版,而後經過蒙版設置可以經過蒙版的圖形部分--> <circle cx="-250" cy="-150" r="100" fill="white"></circle> <circle cx="-200" cy="-200" r="100" fill="black"></circle> </mask> <circle cx="-250" cy="-150" r="100" fill="yellow" mask="url(#moon-mask)"></circle> </g> <!--燈塔--> <g id="light-tower" transform="translate(255, 0)"> <defs> <linearGradient id="tower" x1="0" y1="0" x2="1" y2="0"> <!--設置燈塔漸變--> <stop offset="0" stop-color="#999"></stop> <stop offset="1" stop-color="#333"></stop> </linearGradient> <radialGradient id="light" cx="0.5" cy="0.5" r="0.5"> <!--設置燈光漸變--> <stop offset="0" stop-color="rgba(255, 255, 255,.8"></stop> <stop offset="1" stop-color="rgba(255, 255, 255, 0)"></stop> </radialGradient> <clipPath id="light-clip"> <!--clip裁剪路徑--> <polygon points="0 0 -400 -15 -400 15" fill="rgba(255,0,0,.5)"> <!--動畫效果--> <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" dur="10s" repeatCount="indefinite"> </animateTransform> </polygon> <circle cx="0" cy="0" r="2"></circle> </clipPath> </defs> <polygon points="0 0 5 50 -5 50" fill="url(#tower)"></polygon> <!--光線繪畫:先畫一個橢圓,再畫一個三角形,而後使用三角形對橢圓裁剪--> <ellipse cx="0" cy="0" rx="300" ry="100" fill="url(#light)" clip-path="url(#light-clip)"></ellipse> <!--調用裁剪路徑,用三角形裁剪橢圓,造成光線--> </g> </g> <!--湖面鏡像--> <g id="reflact" transform="translate(0 50)" mask="url(#fading)"> <defs> <linearGradient id="fade" x1="0" y1="0" x2="0" y2="1"> <stop offset="0" stop-color="rgba(255,255,255,.3)"></stop> <stop offset="0.5" stop-color="rgba(255,255,255,0)"></stop> </linearGradient> <mask id="fading"> <rect x="-400" y="0" width="800" height="300" fill="url(#fade)"></rect> </mask> </defs> <use xlink:href="#real" transform="scale(1, -1) translate(0 -50)" /> </g> </svg> <script> var SVG_NS = 'http://www.w3.org/2000/svg'; var XLINK_NS = 'http://www.w3.org/1999/xlink'; var paper = document.querySelector('svg'); renderStar(); function use(origin){ //使用use能夠快速繪畫多種相同的圖形 var _use = document.createElementNS(SVG_NS, 'use'); _use.setAttributeNS(XLINK_NS, 'xlink:href', '#' + origin.id); return _use; } function random(min, max){ return min + (max - min) * Math.random(); } function renderStar(){ var starRef = document.getElementById('star'); var starGroup = document.getElementById('star-group'); var starCount = 500; var star; while(starCount--){ star = use(starRef); star.setAttribute('opacity',random(0.1, 0.4)); star.setAttribute('transform', 'translate(' + random(-400, 400) + ',' + random(-300, 50) + ')' + 'scale(' + random(0.1, 0.6) + ')'); starGroup.appendChild(star); } } </script> </body> </html>
SVG動畫
動畫原理
動畫原理
SVG的動畫原理跟flash的原理是同樣的(之前有玩過flash的就知道了),在不一樣的幀設置不一樣的值,這樣圖形就會隨着時間碎片的增長而產生動畫效果。好比一個矩形,經過時間的差值,一幀一幀的改變設置某一個值好比x值,讓其到達最終值,就會使矩形產生水平移動效果。
值-時間關係圖
from 開始值
to 最終值
duration 動畫時長
timing-function 動畫曲線
frame 幀(1s切成24塊,即24幀/s,人眼看到的就是一個連續的動畫,若是要流暢的話,就60幀/s以上)
interpolation 動畫差值
創造並使用動畫
內部資源標識符定位,即元素的id或class
<animate xlink:href="url(#rect1)"></animate>
包含在目標元素中
<rect x="0" y="0" width="100" height="200"> <animate></animate> </rect>
SMIL for SVG
參考資料:
https://www.zhangxinxu.com/wordpress/2014/08/so-powerful-svg-smil-animation/
https://www.w3.org/TR/SVG/animate.html
動畫標籤:
<animate>基本動畫
-attributeName 能夠是元素名,或者樣式名
-attributeType 表明動畫是對XML屬性(好比元素的位置變化) 仍是 CSS樣式(好比元素的顏色變化)
-from 從開始值
-to 到最終值
-dur 設置動畫時間
-repeatCount 屬性值能夠是數值(好比設置爲100,則重複操做100次),也能夠是indefinite,則一直循環操做
-fill 屬性值freeze表明動畫結束時保存最終值,不會變成開始值,即留在最後的位置;屬性值remove表明動畫結束時刪除最終值,而後變回開始值,即返回開始位置
-begin 定義動畫的開始時間,能夠是數值,表達式
-calcMode
注:動畫是能夠疊加的(好比既能夠設置移動,也能夠設置顏色變化)
<animate attributeType="XML" attributeName="x" from="10" to="100" dur="3s"> </animate>
<animateTransform>變換動畫
-type rotate旋轉 或 scale縮放
-from 從開始值
-to 到最終值
-dur 動畫時間
注:不支持多個動畫重疊
<svg viewBox="-400 -400 800 800"> <rect x="0" y="0" width="100" height="100" fill="red"> <animateTransform id="rotate" attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" dur="3s" > </animateTransform> </rect> </svg>
<animateMotion>軌跡移動
-path 運動軌跡
-dur 動畫時間
-rotate auto 根據路徑的切線變化而旋轉
<svg viewBox="-400 -400 800 800"> <rect x="0" y="0" width="40" height="40" fill="red"> <animateMotion path="M 0 0L 100 100A 200 200 0 1 0 0 -100" dur="5s" rotate="auto" > </animateMotion> </rect> <path id="motion-path" d="M 0 0L 100 100A 200 200 0 1 0 0 -100" stroke="red" fill="none"></path> </svg>
另外一種添加路徑方法 mpath
<svg viewBox="-400 -400 800 800"> <rect x="0" y="0" width="40" height="40" fill="red"> <animateMotion dur="5s" rotate="auto" > <mpath xlink:href="#motion-path"></mpath> </animateMotion> </rect> <path id="motion-path" d="M 0 0L 100 100A 200 200 0 1 0 0 -100" stroke="red" fill="none"></path> </svg>
腳本動畫
requestAnimationFrame(update) 經過腳本在每個時間幀對當前元素屬性的更新
實例:力導向圖(存在引力和排斥力)
實例源代碼:
HTML代碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>力導向圖</title> <style type="text/css"> html,body,svg{ width: 100%; height: 100%; margin: 0; padding: 0; } </style> </head> <body> <svg viewBox="-400 -400 800 800"> <path d="" stroke="gray" fill="none" id="links"></path> </svg> <script type="text/javascript" src="vector.js"></script> <script type="text/javascript"> var points = 'a,b,c,d,e,f,g'.split(",").map(function (name,index,arr) { return { name : name, color : 'hsl(' + (360 * index / arr.length) + ", 100%, 60%)" }; }); var relation = 300; var k = 0.05; var svg = document.querySelector("svg"); var Vector = window.Vector; function random(min,max) { return Math.round(min + (max - min) * Math.random()); } points.forEach(function (point) { var circle = document.createElementNS("http://www.w3.org/2000/svg","circle"); var x = random(-200,200); var y = random(-200,200); circle.setAttribute('cx',x); circle.setAttribute('cy',y); circle.setAttribute('r',10); circle.setAttribute('fill',point.color); svg.append(circle); point.circle = circle; point.s = new Vector(x,y); point.v = new Vector(); point.a = new Vector(); }); // 上一幀時間 +new Date() 至關於 (new Date()).getTime(); var lastFrameTime = +new Date(); function update() { // 當前幀時間 var frameTime = +new Date(); var t = frameTime - lastFrameTime; // 對時間t進行縮放 t /= 100; console.log(t); //點位置更新 points.forEach(function (pa) { var f = new Vector(); //計算協力 points.forEach(function (pb) { if (pa == pb) return; // x爲一個矢量 var x = Vector.fromPoints(pa.s ,pb.s); // 彈性形變長度 var delta = x.length() - relation; // f = k * x; f = f.add(x.normalize(delta * k)); }); pa.a = f; pa.v = pa.v.add(pa.a.multipy(t)).multipy(0.98); pa.s = pa.s.add(pa.v.multipy(t)); pa.circle.setAttribute('cx',pa.s.x); pa.circle.setAttribute('cy',pa.s.y); }); //連線更新 var linkPath = []; points.forEach(function (pa) { var sa = pa.s; points.forEach(function (pb) { if (pa == pb) return; var sb = pb.s; linkPath = linkPath.concat([ "M",sa.x,sa.y, "L",sb.x,sb.y, ]); }); }); document.getElementById('links').setAttribute('d',linkPath.join(' ')); lastFrameTime = frameTime; window.requestAnimationFrame(update); } window.requestAnimationFrame(update); </script> </body> </html>
js代碼:
;(function () { function Vector(x,y) { this.x = x || 0; this.y = y || 0; } Vector.prototype = { constructor: Vector, square : function () { return this.x * this.x + this.y * this.y; }, length : function () { // 返回平方根 return Math.sqrt(this.square()); }, add : function (q) { return new Vector(this.x + q.x,this.y + q.y); }, minus : function (q) { return new Vector(this.x - q.x,this.y - q.y); }, multipy : function (scale) { return new Vector(this.x * scale,this.y * scale); }, normalize : function (length) { if (length === undefined) { length = 1; } return this.multipy(length / this.length()); } }; Vector.fromPoints = function (p1,p2) { return new Vector(p2.x - p1.x, p2.y - p1.y); }; window.Vector = Vector; })()
效果圖
本文內容是我自學的知識整理,其中的一些理解不必定正確,但願你們仍是可以本身學習一下而後有本身的看法,若是與個人理解不一致,也但願可以留言指正。
附學習網址: