初窺基於 react-art 庫的 React Native SVG

技術背景

在移動應用的開發過程當中,繪製基本的二維圖形或動畫是必不可少的。然而,考慮到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

原理和調用

獲取ART

package.json中須要引入art庫,筆者的版本設置是react-art: 0.14.0json

Android與iOS

var React = require('react-native');
var ReactART = React.ART;

或者使用ES6的Destructuring特性:canvas

var {
    ...,
    ART,
    ...,
} = React;

Web端

var React = require('react');
var ReactART = React.ART;

基本組件

獲取方式

接下來的所述的代碼,web端和移動端都是通用的,這也是React Native的誘惑所在。react-native

var {
    Shape,
    Group,
    Transform,
    Surface,
    ...,
} = React.ART;

Surface

全部的svg component必須被一個Surface標籤所包含。
Props以下:

  • width: Surface的寬度。

  • height: Surface的高度。

  • style: margin系列和padding系列都生效。

Group

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

Shape用於生成路徑,語法與svg中的<path>很類似。Shape的Props以下:

  • d: 語法與svg規範相同

  • stroke: 線條顏色,"#FFFFFF"的形式

  • strokeWidth: 線條寬度,{3}的形式

  • transform:接受 new ART.Transform()生成的object,具體見下文Transform條目。

Path

語法更近似於移動端。使用方法:

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個,你這裏沒有光滑三次啊?由於開發的同窗留坑沒寫了呀(微笑)。

Transform

實現代碼路徑: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

引入lib中的module

在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

使用示例:

<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

使用示例:

<Rectangle
  width={200}
  height={400}
  stroke="red"
  strokeWidth={10}
  fill="FFFFFF"
/>

使用上述代碼,就很直觀看到這個module的缺陷了,矩形四條邊不等寬(扶額)。
圖片描述
此外還接受的props有:

  • radius

  • radiusTopLeft

  • radiusTopRight

  • radiusBottomLeft

  • radiusBottomRight

這裏的radius指的是圓角矩形的圓角半徑,接受的值類型爲數字,radius爲四個角的通用半徑,但若是設置了具體某個角的半徑,則用後者。

Wedge

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

相關文章
相關標籤/搜索