在移動應用的開發過程當中,繪製基本的二維圖形或動畫是必不可少的。然而,考慮到Android和iOS均有一套各自的API方案,所以採用一種更廣泛接受的技術方案,更有利於代碼的雙平臺兼容。css
art是一個旨在多瀏覽器兼容的Node style CommonJS模塊。在它的基礎上,Facebook又開發了react-art ,封裝art,使之能夠被react.js所使用,即實現了前端的svg庫。然而,考慮到react.js的JSX語法,已經支持將<cirle>
<svg>
等等svg標籤直接插入到dom中(固然此時使用的就不是react-art庫了)此外還有HTML canvas的存在,所以,在前端上,react-art並不是不可替代。html
然而,在移動端,考慮到跨平臺的需求,加之web端的技術積累,react-art成爲了現成的繪製圖形的解決方案。react-native分別在0.10.0和0.18.0上添加了iOS和Android平臺上對react-art的支持,固然,沒有文檔。在文檔基本等於沒有的狀況下,筆者苦逼地翻源代碼,爲你們帶來了(全球首發?=_=)的入門文檔。前端
推薦你們採用react-art自帶的Example: Vector-Widget。React.js和React-Native的區別,只在於下文所述的ART獲取上,而後該例子就能夠同時應用在Web端和移動端上了。react
成功運行Vector-Widget後的效果圖:
git
Vector-Widget額外實現了旋轉,以及鼠標點擊事件的旋轉加速響應。Web端能夠看到點擊加速,可是在移動端無效,緣由是React Native並未對Group中onMouseDown和onMouseUp屬性做處理。本文着重於靜態svg的實現,暫時無視動畫部分效果便可。github
此外還能夠用該例子感覺一下歎爲觀止svg動畫的性能佔用(攤手)。web
package.json中須要引入art庫,筆者的版本設置是react-art: 0.14.0
。json
var React = require('react-native'); var ReactART = React.ART;
或者使用ES6的Destructuring特性:canvas
var { ..., ART, ..., } = React;
var React = require('react'); var ReactART = React.ART;
接下來的所述的代碼,web端和移動端都是通用的,這也是React Native的誘惑所在。react-native
var { Shape, Group, Transform, Surface, ..., } = React.ART;
全部的svg component必須被一個Surface標籤所包含。
Props以下:
width: Surface的寬度。
height: Surface的高度。
style: margin系列和padding系列都生效。
Group用於組合art component。好比在一個函數中返回多個svg component的狀況,此時就必需要用<Group>
包一下,不然即報錯。<Group>
能夠嵌套使用。
style:margin和padding系列均無效,我懷疑不接受style。
function _render() { return ( <Group> <Shape d={"M160 160 A 45 45, 0, 0, 1, 115 205"} stroke="#000000" strokeWidth={3} /> <Shape d={"M160 160 A 45 45, 0, 0, 1, 115 205"} stroke="#000000" strokeWidth={3} /> </Group> ); }
Shape用於生成路徑,語法與svg中的<path>很類似。Shape的Props以下:
d: 語法與svg規範相同
stroke: 線條顏色,"#FFFFFF"的形式
strokeWidth: 線條寬度,{3}的形式
transform:接受 new ART.Transform()生成的object,具體見下文Transform條目。
語法更近似於移動端。使用方法:
var ReactART = require('./ReactART'); var Path = ReactART.Path; function _render() { // 除close之外的全部方法都返回修改後的自身,所以支持鏈式調用 var path = Path().moveTo(0, -radius) .arc(0, radius * 2, radius) .arc(0, radius * -2, radius) .close(); // path能夠直接賦值給d return <Shape d={path} /> }
能夠看到,取出的Path是一個構造函數。Path對象的中的函數功能以下,大多與svg規範一致,我就再囉嗦一遍了。svg規範中<path>的d屬性請參見https://developer.mozilla.org/en-US/docs... :
push():
reset(): 清空Path
move(x, y): 等同於'm',移動到目的座標,參數x和y是相對目標下的目的座標
moveTo(x, y): 等同於'M',與move只差異在x和y是絕對座標。
line(x, y): 等同於'l',從一個座標點到另外一個座標點畫直線,參數x和y是相對座標下的目的座標
lineTo(x, y): 等同於'L',與line只差異在x和y是絕對座標。
arc(x, y, rx, ry, outer): 等同於'a',從一個座標點向另外一個座標點畫橢圓曲線,x和y是相對座標下的目的座標,rx和ry是橢圓的長軸半徑和短軸半徑,outer只有0和1兩個數字,表明是大角度仍是小角度。
arcTo(x, y, rx, ry, outer): 等同於'A',與arc只差異在x和y是絕對座標。
curve(2個,4個或6個參數): 從一個座標點向另外一個座標點畫貝塞爾曲線。
當參數爲兩個時,等同於't',繪製光滑二次貝塞爾曲線。
當參數爲4個時,等同於'q',繪製二次貝塞爾曲線。
當參數爲6個時,等同於'c',繪製三次貝塞爾曲線。
有些精通SVG的同窗這時候可能就要問我了,不對啊,二次貝塞爾曲線和光滑三次貝塞爾曲線的參數都是4個,你這裏沒有光滑三次啊?由於開發的同窗留坑沒寫了呀(微笑)。
實現代碼路徑:art/core/transform.js
Transform對象中的函數:
transform(xx, yx, xy, yy, x, y): transform的相對座標版本
transformTo: 完整的矩陣變換,把這張位圖上全部的點都作一次矩陣乘法,獲得的新位圖,公式以下圖所示$$ \begin{Bmatrix} a & b & c \\ d & e & f \\ 0 & 0 & 1 \\ \end{Bmatrix} \times \begin{Bmatrix} x \\ y \\ 1 \end{Bmatrix}$$
translate(x, y): 位移
move: 相對於原參考點座標,增減參考點的x,y座標
moveTo: 等同於translateTo,容易誤覺得是move的絕對左邊版本,吐糟不能
scale(x, y): 將一個元素拉伸或者壓縮指定的倍數,x是寬度縮放比例,y是長度縮放比例,若是隻有一個參數,則x = y。如
scaleTo: 在縮放的同時保持原來的長寬比。例子和效果圖以下:
<Surface width={700} height={700}> <Rectangle width={100} height={200} stroke="red" strokeWidth={10} fill="FFFFFF" transform={new Transform().translate(150, 150).scale(2)} /> <Rectangle width={100} height={200} stroke="yellow" strokeWidth={10} fill="FFFFFF" transform={new Transform().translate(150, 150).scaleTo(1, 2)} /> <Rectangle width={100} height={200} stroke="blue" strokeWidth={10} fill="FFFFFF" transform={new Transform().translate(150, 150)} /> </Surface>
rotate(deg, x, y): 將一個元素旋轉角度deg。x和y則是用於指定旋轉的原點。
<Surface width={700} height={700}> <Rectangle width={100} height={200} stroke="red" strokeWidth={10} fill="FFFFFF" transform={new Transform().translate(150, 150)} /> <Rectangle width={100} height={200} stroke="red" strokeWidth={10} fill="FFFFFF" transform={new Transform().translate(150, 150).rotate(30, 100, 100)} /> </Surface>
<Surface width={700} height={700}> <Rectangle width={100} height={200} stroke="red" strokeWidth={10} fill="FFFFFF" transform={new Transform().translate(150, 150)} /> <Rectangle width={100} height={200} stroke="red" strokeWidth={10} fill="FFFFFF" // 差異在這裏 transform={new Transform().translate(150, 150).rotate(30)} /> </Surface>
效果以下圖所示:
在react-art的庫中,有個神奇的lib文件夾,下面除了ReactART.js之外,還有Circle.art.js,Rectangle.art.js,Wedge.art.js等,其中Circle和Rectangle分別對應於svg規範中的圓形<circle>
,矩形<rect>
,而Wedge則是用於生成扇形。固然,這些module都很不完善,頗有可能須要二次開發,若是這樣,推薦拷貝庫文件到工程中再行修改。
引入它們的語句爲var Circle = require('react-art/lib/Circle.art');
。這種不一樣尋常地引用方式是Facebook開發和維護的fbjs引入的,react-native依賴了fbjs,而全部須要被輸出的js文件的頭部都會以// @providesModule Circle.art
的形式標明。
使用示例:
<Circle radius={10} stroke="green" strokeWidth={3} fill="blue" />
值得一提的是,Circle.art.js是個半成品,能夠看到它根本沒有實現svg規範中的cx和cy,所以畫出來的圓的圓心始終在左上角,顯示出來的也就只有半個圓。請在實際應用中自行實現,或者使用筆者提供的修改版本。
固然,不用cx和cy的話,也能夠設置tranform來實現平移。如:
<Circle radius={10} stroke="green" strokeWidth={3} fill="blue" transform={new Transform().translate(100, 100)} />
兩種方法均可以達到平移效果,可是cx, cy的方式相對來講更簡潔,可讀性也更好。
使用示例:
<Rectangle width={200} height={400} stroke="red" strokeWidth={10} fill="FFFFFF" />
使用上述代碼,就很直觀看到這個module的缺陷了,矩形四條邊不等寬(扶額)。
此外還接受的props有:
radius
radiusTopLeft
radiusTopRight
radiusBottomLeft
radiusBottomRight
這裏的radius指的是圓角矩形的圓角半徑,接受的值類型爲數字,radius爲四個角的通用半徑,但若是設置了具體某個角的半徑,則用後者。
Wedge是楔子的意思,然而在這裏倒是生成各類角度的扇形=_=。
使用示例:
<Wedge outerRadius={50} stroke="red" startAngle={0} endAngle={100} fill="FFFFFF" />
生成的圖形以下圖:
可選Props爲innerRadius,用於生成一個圓環扇形,以下圖。
吶,一看這個module也是半成品,若是stroke有顏色而fill爲白色就露餡了,曲線沒閉合。所以,若有需求,請自行彌補。
除了以前所提到的各類各樣的實現上的不完善之外,svg規範在React Native上應用的最大問題在於,有一大批web上的svg支持的css屬性,尚未在React Native上實現。
以stroke類的一大批屬性爲例,目前可用的只有線條顏色stroke和strokeWidth,而如stroke-dasharray,stroke-dashoffset這樣的能夠用之實現神奇的描邊等效果的CSS屬性,目前尚未被支持。
在性能佔用方面, 靜態svg尚可接受,但若是是svg annimation,實測紅米Note 2上的CPU佔用率便可達50%左右,故其在生產環境的大規模應用,恐怕還需進一步的性能優化。
====================================
若是您以爲個人文章對您有所啓迪,請點擊文末的推薦按鈕,您的鼓勵將會成爲我堅持寫做的莫大激勵。 by DesGemini