TP Notes
全部
CSS
SVG
資源收集
HTML
其它
關於我
Translate
2020年12月7日 星期一
SVG 與 javascript
SVG 可以很不錯的和 CSS 整合在一起,那麼來看看和 javascript 相關的 API # 動畫控制 SVG 的動畫控制上,針對單一動畫很奇怪的沒有 **暫停** 這個功能,只能對全部的 SVG 動畫全部暫停 指令 : ``` svg.pauseAnimations(); svg.unpauseAnimations(); ``` 範例如下: ``` $mmcode(r0) ```
暫停
繼續
對於單一動畫比較會用到的 API 有這些 ``` getCurrentTime() - 取得目前動畫的時間 beginElement() - 開始動畫 beginElementAt(時間) - 在時間(秒)後開始動畫 endElement() - 停止動畫 endElementAt(時間) - 在時間(秒)後停止動畫 EVENT 的部份有這三個 beginEvent - 動畫開始時 endEvent - 動畫停止時 repeatEvent - 動畫重覆時 ``` 先來一個簡單的範例,範例中每 100ms 更新一次狀態,用下面這段程式碼來取得動畫執行中的 x 座標,如果要設定計 **暫停** 的功能,必須先取得座標,在下次執行時從這裡開始,然而這個解法有很多問題,最理想的還是等 SVG 的動畫新增暫停的指令 ``` document.getElementById("a120701_r1").x.animVal.value; ``` ``` $mmcode(r1) ```
點我開始
點我停止
動畫時間 :
x 座標 :
$textarea id="a120701_status" style="width:300px;height:100px"> $/textarea>
既然可以用 javascript 控制,那麼先來修改一下上一篇的時鐘,來把時間調成目前時間 ``` $mmcode(r2) ```
# 新增物件 SVG 由於命名空間的問題,用 html 的 append 新增html字串時不會有反應, 之前用過一個技巧,就是重寫裡頭的 html 來產生效果,其實更正確的方式是,建立一個屬於 svg 命名空間的物件,就可以用 append 加入了,方法如下: ``` var obj=document.createElementNS('http://www.w3.org/2000/svg', "tag 名稱,例如 rect"); 建立 obj 後可以用 obj.setAttribute("參數",值); 或用 jquery $(obj).attr("參數",值); ``` 範例如下: ``` $mmcode(r3) ```
用append新增
重新寫入html
用createElementNS新增
2020年12月2日 星期三
SVG 動畫
SVG 的動畫相當有趣也相當靈活,甚至可以互動,感覺上已經超越單純的動畫了 跟動畫相關的指令有 set, animate, animateTransform, animateMotion # set 首先先來一個 set 的範例 ``` attributeName="屬性" begin="開始的時機" to="要改的值" ``` begin 可以用 1s(1秒) , 100ms (0.1秒) , 或各種 event, 當時機為 **時間** 時,代表的是該物件出現後開始計算時間 詳細的資料可以看[這裡](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/begin) ``` $mmcode(r1) ```
GO
# animate ``` attributeName="屬性" begin="開始的時機" end="結束的時機" from="開始的值",(可以用 values 取代) to="結束的值",(可以用 values 取代) by="相對from的值",例如 from="30", to="50" 最後的值是 50 , 如果用 by="50" , 最後的值是 80 values="要改變的值" ,可以用分號區挌,指定多個值,例如: "10;50;10" keyTimes="運行時間比",用分號區格,為 0 到 1 的數值,用來指定每一個 values 運行時間 keySplines="貝式曲線的時間",四個值,和 css 的 Cubic Bezier 很像,必須設定 calcMode="spline" 才有作用 calcMode="模式",discrete, linear (預設) , paced, spline dur="時間" max="時間",動畫執行到這個時間後停止 repeatCount="重覆次數",indefinite 為不斷重覆 restart="觸發 begin 後的動作",always(預設),whenNotActive(啟動狀態不重新開始),never(不重新啟動) fill="end 觸發後的狀態",freeze(凍結在目前狀態),remove(回到初始狀態) accumulate="累加",none(預設),sum(累加), 在累加狀態時,動畫 repeat 不會回到初始狀態 ``` 先來一個簡單的範例,values 和 keyTimes 的數量必須一樣,keyTimes 的時間比由 0 到 1 ,數值必須越來越大 紅色方塊沒有設定 keyTimes ,時間比例和數值是平均分布, 等同 keyTimes="0;0.33;0.67;1"
紫色方塊設定 calcMode="discrete",沒有動畫直接跳過去
綠色方塊設定 keyTimes="0;0.6;0.9;1" ,一開始走很慢,後面跑很快
橘色方塊設定 calcMode="paced" , 行走速度不受分段影響
藍色方塊設定了 keySplines ,要記得加上 calcMode="spline" ``` $mmcode(r2) ```
# begin , end svg 動畫中的 begin 和 end 很有意思,可以做到基本的互動,讓動晝不再只是動畫,
可以用 `
click
` 來觸發 begin ,也可以從 html 去觸發,方法如下:
詳細 API 可以參考[這裡](https://developer.mozilla.org/en-US/docs/Web/API/SVGAnimationElement) ``` document.getElementById('animate ID').beginElement(); ``` begin 和 end 的值如下: ``` 時間(1s,100ms) 時間到開始執行 id.[event] 例如 id.click ,當 id 被點擊時觸發,可以用 id.click+1s 表示點擊後過1秒 id.begin 當 id 動畫開始時 id.end 當 id 動畫結束時 id.repeat(n) 當 id 動畫重覆 n 次後,(經實測,在 iphone 及 safari 無作用) [event 列表] focus, blur, focusin, focusout, activate, auxclick, click, dblclick, mousedown, mouseenter, mouseleave, mousemove, mouseout, mouseover, mouseup, wheel, beforeinput, input, keydown, keyup, compositionstart, compositionupdate, compositionend, load, unload, abort, error, select, resize, scroll, ``` 來看一個範例 ``` $mmcode(r3) ```
HTML 的點我開始
點我開始
點我停止
方塊一
方塊二
# accumulate 這個累加的設定,我還沒想到應用的地方,範例如下 : 每次 repeat 顏色都會改變,有加 accumulate="sum" 的方塊,在 repeat 時並沒有回到初始狀態, 而是以當前位置為原點,by=10 跑到 by=50 (以第一次 repeat 來說,會從 x=60 開始) 這個範例在 chrome 和 firefox 的結果又有點不同,我覺得 firefox 比較正確 ``` $mmcode(r4) ```
accumulate="none"
accumulate="sum"
# animateTransform 除了本來 animate 的參數外,還多了幾個 ``` type="transform 的種類" additive="取代或累加",replace(預設), sum(效果累加) ``` 範例如下 : ``` $mmcode(r5) ```
圖1: 設定 transform scale 從 1 到 2
圖2: 設定 transform scale 從 1 到 2 ,並且 translate 移動方塊中心點,這個時候必須加上
additive="sum"
,兩個 transform 的設定才會累加
# animateMotion 這個功能相當有趣,可以規劃一條路徑,讓物件跟著路徑跑,除了本來 animate 的參數外,還多了一些參數 ``` path="和 path 的 d 相同" rotate="角度",auto(隨著路線自動轉)|auto-reverse(隨著路線自動轉再加 180 度) keyPoints="設定中間點",為 0 到 1 的值,搭配 keyTimes 來調整每一段的速度,要記得設定 calcMode 才有作用 ``` 除了參數外,在 animateMotion 中可以使用 mpath 來取代參數 path , 這樣可以利用 xlink:href 來使用別處定義好的路徑 先來一個範例: 紅球用參數 path 來設定路徑,藍色方塊和綠三角使用 mpath 來串接 #a12026_p1 這條路徑, 綠三角有設定 keyPoints 和 keyTimes,讓路徑不同區段有不同速度 ``` $mmcode(r6) ```
那麼最後就用一個SVG的時鐘做為這一篇的結束 ``` $mmcode(r7) ```
2020年11月27日 星期五
SVG 的文字
以前自己開發繪圖函式庫時,字都是自己畫,一開始是抓倚天中文的字形檔,後來用自己的方式產生自己的字形檔,並加上 alpha 來做反鋸齒,當時還為了開發泰國版本,自行設計泰文輸入法,雖然可以使用 truetype 字形,但是當時硬體規格太差,為了速度,還是要自己寫效率比較高,現在看到 SVG 文字相關的定義,真的覺得當初自己所想到的功能太陽春,SVG 的規劃要完整多了。 ## text 的參數如下: ```css x,y 座標 dx,dy 偏移 rotate 旋轉 lengthAdjust spacing (預設) 字與字之間以空白做間隔 spacingAndGlyphs 字與字之間以變形填滿 textLength 字串長度 text-anchor start , middle , end 文字定位 以下參數也可以做為 CSS 的參數 dominant-baseline auto (預設) text-bottom alphabetic ideographic middle central mathematical hanging text-top writing-mode horizontal-tb vertical-rl vertical-lr ``` 先來一個簡單範例 ``` $mmcode(r1) ```
1a
1a
可以發現,SVG 的字完全就是用畫的,像多邊形一樣,所以右邊的文字有加上 `stroke-linejoin="round"` 在角落的地方就成了圓角 文字處理另一個麻煩的就是基準線,這裡使用的是 dominant-baseline ,可以當作參數,也可以當作 CSS 使用
auto
測試1a
CSS 的文字有個很特別的設計,利用類似陣列的方式為每一個字設定屬性 ``` $mmcode(r3) ```
abcde
也可以用 dx 和 dy 做偏移 ``` $mmcode(r4) ```
abcde
可以用 rotate 旋轉, 而旋轉預設的中心點在左下角 ``` $mmcode(r5) ```
abcde ddd
textLength 和 lengthAdjust 搭配,設定字串長度後,看要用空白還是變形的方式填空間 ``` $mmcode(r6) ```
abcde
abcde
abcde
直寫測試123
# tspan 當一段文字想要有不同設定時,可以用 tspan ,就如同 css 的 span 一樣,搭配 dominant-baseline 就可以做到上標字和下標字的效果,
*經實測結果 Firefox 會不正常顯示
,以下正確結果應該顯示為
X₂+Y²=Z⁽²ⁿ⁺¹⁾
``` $mmcode(r7) ```
abc
123
def
def
ghi
X
2
+Y
2
=Z
(2n+1)
如果要完全相容的上標和下標字,似忽只有利用 dy 來實作,但是這個缺點就是,沒辦法單純用 css 來完成,而且 `
` 的定義很奇怪,一但 dy 改變了,就是改變了,並不會在 `
` 時變回來,所以在使用上標字(dy 減去某個值) ,必須在下一個顯示的字把 dy 的值加回來。 ``` $mmcode(r8) ```
X
2
+Y
2
=Z
(2n+1)
為了處理上標和下標問題,只好利用 javascript 來協助,加上 svgsup 和 svgsub 兩個 class ,由 javascript 來處理 dy 的問題,程式碼很簡單,效果也不錯 ``` $mmcode(svgsup) ```
X
2
+Y
2
=Z
(2n+1)
# textPath SVG 有個有趣的東西叫 textPath ,文字可以隨著路徑跑,這個功能當初我在設計網頁上的向量地圖時曾經用來顯示路名 當初在寫導航程式顯示路名時,字隨路徑走是用比較偷懶的方式,計算出每個字的座標,但是字不會旋轉,隨著現在硬體規格越來越強,加上 SVG 有這麼方便的指令,要開發 2D 地圖真的簡單多了。 ``` $mmcode(r9) ```
文字可以隨著路徑跑
startOffset="100"
可以使用
tspan
來做效果
這個設定在 iPhone 及 safari 沒用
dominant-baseline="central"
直式書寫 writing-mode:vertical-lr;
文字可以隨著路徑跑,那麼是不是可以取得路徑長度後,計算每個字的間距,讓字平均分布呢 ? 方法如下 : ``` let pp = document.getElementById("[path 的 ID]"); let len = pp.getTotalLength(); //取得路徑總長度 let xy = pp.getPointAtLength(500); //取得距離 500 的點位 , return {x:n,y:m} let box = pp.getBBox(); //取得路徑範圍 , return {x:n,y:n,width:n,height:n} ``` 取得長度後就可以計算平均分布的位置 ``` $mmcode(r10) ```
文字可以隨著路徑跑喲
較新的文章
較舊的文章
首頁
訂閱:
文章 (Atom)