初識(shí)SVG

最近遇到一個(gè)關(guān)于彩票中獎(jiǎng)號(hào)碼展示的項(xiàng)目,里面有很多技術(shù)難點(diǎn),其中一個(gè)就是把各開(kāi)獎(jiǎng)號(hào)碼之間用線段連接起來(lái),這是一個(gè)典型網(wǎng)頁(yè)圖形繪制問(wèn)題。本文嘗試講解如何利用SVG技術(shù)實(shí)現(xiàn)折線圖形的繪制。

我們知道,在網(wǎng)頁(yè)中繪制圖形有很多種方式,如canvas、svg、vml等都可以繪制優(yōu)秀的矢量圖形。關(guān)于它們的區(qū)別和適用性比較,可以參考這篇文章,本文只介紹如何使用SVG的基礎(chǔ)知識(shí)實(shí)現(xiàn)我的工作目的。

首先分析下問(wèn)題和解決方案

彩票號(hào)碼一般都顯示為圓形的小球,上面疊加一個(gè)阿拉伯?dāng)?shù)字。要把一系列小球用直線連接,需要知道每個(gè)小球的位置信息,然后用SVG的line方法畫出來(lái)。

那么問(wèn)題來(lái)了,我們?cè)趺床拍艿玫叫∏虻奈恢眯畔⒛兀?/strong>

一般計(jì)算機(jī)的坐標(biāo)系都是以左上角為原點(diǎn),橫向?yàn)閄軸,縱向?yàn)閅軸。SVG坐標(biāo)系也不例外。

此外,我們把小球都放表格中,并規(guī)定好單元格的寬高。以表格的左上角為原點(diǎn),就能輕松得到每個(gè)單元格的XY軸信息,進(jìn)而得到圓心的坐標(biāo)。very nice!

svg坐標(biāo)系

但實(shí)際上我們只得到圓心的坐標(biāo)是不行的,因?yàn)镾VG層疊加在表格上面,如果用Line方法把各個(gè)圓心連接起來(lái),會(huì)把小球上面的文字蓋住。所以Line的起止坐標(biāo)必須在小球的邊緣上。而且,除了第一個(gè)和最后一個(gè)小球外,每個(gè)小球都要有一個(gè)畫入點(diǎn)和一個(gè)畫出點(diǎn),分別指向它的上一個(gè)小球和下一個(gè)小球。

那么問(wèn)題又來(lái)了,怎樣才能得到這些出入點(diǎn)的坐標(biāo)呢?

思前想后,終于把這個(gè)問(wèn)題抽象為一道數(shù)學(xué)題:已知一個(gè)圓的圓心坐標(biāo)和半徑,有一條從圓心發(fā)出的直線,假設(shè)直線與X軸的夾角為a,求該直線與圓相交的點(diǎn)的坐標(biāo)。

Oh My Dog!這特么解析幾何??!哥中學(xué)課本早燒香了,咋辦?
zzz...


沒(méi)辦法,自己畫吧。在紙上算啊算,電腦上測(cè)啊測(cè),終于憋出一個(gè)公式!

想要草稿紙的自行來(lái)取

寫成函數(shù)如下:
<code>
function calcPointCoor(cx,cy,r,alpha){
//cx,cy: coordination of the circle
//r: radius
//alpha: angle of line and X axis
return {x:cx + r * Math.cos(alpha),y:cy + r * Math.sin(alpha)};
}
</code>
其中cx,cy是圓心坐標(biāo),r是半徑,alpha為角度。

然而如何計(jì)算兩個(gè)小球之間的角度呢?

還解析幾何?。∠氲侥X細(xì)胞會(huì)燒壞一坨,還是算了。我考慮用Snap SVG組件的angle方法來(lái)做,這個(gè)方法只要兩個(gè)點(diǎn)的x,y坐標(biāo),就能返回他們之間的夾角。

要注意的是,給angle方法傳入的參數(shù)順序不同,得出的角度會(huì)有差別。經(jīng)過(guò)測(cè)試,angle方法得出的角度值是自X軸正向順時(shí)針增加的。這樣,如果要按解析幾何平面坐標(biāo)系來(lái)計(jì)算的話,就需要加入或減去一個(gè)π周期來(lái)修正。

另外,還需要把角度值轉(zhuǎn)換為弧度值。因?yàn)镴S中Math對(duì)象的正余弦函數(shù)只接受弧度值。

經(jīng)過(guò)上帝測(cè)試,最終得出以下方法:
<pre><code>
//radius , coordinations of current cicle and next circle
var r,cur_cx,cur_cy,next_cx,next_cy;

//.....

var ang = Snap.angle(next_cx,next_cy,cur_cx,cur_cy) * Math.PI / 180;

var coor1 = calcPointCoor(cur_cx,cur_cy,r, ang);

var coor2 = calcPointCoor(next_cx,next_cy,r, ang + Math.PI);

var c = svg.path("M" + coor1.x + " " + coor1.y + "L" + coor2.x + " " + coor2.y).attr({stroke:stroke_color,strokeWidth:1.5});</code></pre>

這里面的coor1是當(dāng)前小球到下一個(gè)小球的畫出點(diǎn)坐標(biāo),coor2是下一個(gè)小球的畫入點(diǎn)坐標(biāo)。

再往下就簡(jiǎn)單了,SVG中有Line方法,只要循環(huán)一下某一組中所有中獎(jiǎng)號(hào)碼的小球圓心坐標(biāo),就可以搞定一切。

但實(shí)際應(yīng)用中,Path方法比Line方法更高效。因?yàn)楫嬕欢尉€條就得用一個(gè)Line,而Path方法只要給出d屬性的M和L值,就可以在一個(gè)標(biāo)簽中實(shí)現(xiàn)N段線條,然后你就能方便地切換顯示了。哈哈!

svg實(shí)現(xiàn)折線

總結(jié):

  • SVG可以像使用其他HTML標(biāo)簽一樣來(lái)靈活生成,不管你是用PHP還是JavaScript。
  • 對(duì)CSS有效的標(biāo)簽同樣適用于SVG標(biāo)簽。
  • 能用組件或庫(kù)的盡量用,否則死很多腦細(xì)胞

文中涉及的技術(shù)和組件哥也是現(xiàn)學(xué)現(xiàn)賣,歡迎批評(píng)指正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在React Native中使用ARTReact Native ART 究竟是什么?所謂ART,是一個(gè)在React...
    JackfengGG閱讀 9,667評(píng)論 2 50
  • 一:什么是SVG? 對(duì)于SVG的定義如下: ①:SVG 指的是可伸縮矢量圖形 (Scalable Vector G...
    GreenHand1閱讀 916評(píng)論 0 1
  • 一.什么是SVG? SVG 指的是可伸縮矢量圖形 (Scalable Vector Graphics),它用來(lái)定義...
    nightZing閱讀 17,535評(píng)論 11 62
  • SVG 學(xué)習(xí)筆記 SVG是什么 SVG 指可伸縮矢量圖形 (Scalable Vector Graphics) S...
    Penn_Xu閱讀 1,136評(píng)論 0 1
  • 既然了解了運(yùn)營(yíng)就是做好產(chǎn)品與用戶之間的橋梁,那么什么樣的“術(shù)”可以幫我們思考的更全面,將工作做得更細(xì)致,數(shù)據(jù)更好看...
    桔次郎閱讀 509評(píng)論 2 2

友情鏈接更多精彩內(nèi)容