天小編將分享前端開發中必學的知識點,HTML5中關于Canvas(畫布)的知識點;
Canvas,是HTML5中所有新特性目前應用最廣泛的一個標簽,替代引入的圖片(圖形),用途非常廣泛如(因此這個標簽相當重要):
1.完成HTML頁面中的圖形繪制
2.實現網絡游戲或單機游戲(網頁游戲)
3.在HTML頁面中繪制圖表
4.餅狀圖
5.柱狀圖
6.折線圖
7.網頁游戲
...
Canvas的發展方向,目前主流的游戲開發引擎之一,如:白鷺引擎 - HTML5、Cocos-JS - HTML5、掌握物理系統、掌握精靈系統(地圖)、HTML5網頁游戲。
需要特別注意的是:Canvas作為HTML頁面的元素出現、在Canvas繪制的圖形與HTML頁面是無關的、利用DOM定位繪制的圖形、元素的事件不能綁定繪制的圖形
HTML頁面部分:定義<canvas>元素、建議使用width和height屬性設置<canvas>元素的寬度和高度
JavaScript部分:獲取HTML頁面中的<canvas>元素、通過getContext()方法創建畫布對象、該方法接收一個參數 - 創建二維或三維圖形
需要特別注意的是:該參數為字符串類型、"2d"或"3d"中的"d"必須小寫、目前幾乎都是"2d"效果、使用Canvas提供的API完成需求。
fillRect(x,y,width,height) - 繪制實心矩形
x和y - 表示繪制矩形的左上角的坐標值(x,y)
width - 表示繪制矩形的寬度
height - 表示繪制矩形的高度
strokeRect(x,y,width,height) - 繪制空心矩形
x和y - 表示繪制矩形的左上角的坐標值(x,y)
width - 表示繪制矩形的寬度
height - 表示繪制矩形的高度
clearRect(x,y,width,height) - 清除指定區域的矩形
x和y - 表示繪制矩形的左上角的坐標值(x,y)
width - 表示繪制矩形的寬度
height - 表示繪制矩形的高度
設置樣式
fillStyle - 設置填充樣式
strokeStyle - 設置描邊樣式
globalAlpha - 設置透明度(0-10-100-10-1000-10-1000000-10-10000-10-10000-10-10000-10-10000-10-1000-10-100000-100-100-1)
需要特別注意的是:先設置樣式,再繪制圖形,每改變一次樣式,都需要重新設置樣式,填充樣式與描邊樣式互不干擾
createLinearGradient(x1,y1,x2,y2)
線性漸變具有一個基準線
射線(扇形)漸變
createRadialGradient(x1,y1,r1,x2,y2,r2)
射線漸變具有兩個基準圓
設置漸變顏色
addColorStop(position,color)方法
color - 顏色
實現步驟如下:
1.設置線性漸變或扇形漸變
2.返回漸變對象
3.漸變對象設置漸變的顏色
4.設置填充或描邊樣式為漸變
設置屬性:font - 用法與CSS中的font一致
對齊方式:
textAlign - 水平對齊
left - 基準線在文字的左邊
center - 基準線在文字的中間
right - 基準線在文字的右邊
textBaseline - 垂直對齊
top - 基準線在文字的上邊
middle - 基準線在文字的中間
bottom - 基準線在文字的下邊
hanging - 懸掛基線
alphabetic - 字母基線
繪制方法
fillText(text,x,y) - 繪制實心文字
text - 設置繪制的文字內容
x和y - 設置繪制文字的坐標值
strokeText(text,x,y) - 繪制空心文字
text - 設置繪制的文字內容
x和y - 設置繪制文字的坐標值
設置陰影
shadowColor - 設置陰影顏色
shadowOffsetX - 設置陰影水平位置
正值 - 陰影向右移動、0 - 陰影不移動、負值 - 陰影向左移動
shadowOffsetY - 設置陰影垂直位置
正值 - 陰影向下移動、0 - 陰影不移動、負值 - 陰影向上移動
shadowBlur - 設置陰影的程度
值的類型為Number、值越大,陰影效果越明顯
VG 動畫有很多種實現方法,也有很大SVG動畫庫,現在我們就來介紹 svg動畫實現方法都有哪些?
SVG animation 有五大元素,他們控制著各種不同類型的動畫,分別為:
1.1、set
set 為動畫元素設置延遲,此元素是SVG中最簡單的動畫元素,但是他并沒有動畫效果。
使用語法:
<set attributeName="" attributeType="" to="" begin="" />
eg:繪制一個半徑為200的圓,4秒之后,半徑變為50。
<svg width="320" height="320">
<circle cx="0" cy="0" r="200" style="stroke: none; fill: #0000ff;">
<set attributeName="r" attributeType="XML" to="50" begin="4s" />
</circle>
</svg>
1.2、animate
是基礎的動畫元素,實現單屬性的過渡效果。
使用語法:
<animate
attributeName="r"
from="200" to="50"
begin="4s" dur="2s"
repeatCount="2"
></animate>
eg:繪制一個半徑為200的圓,4秒之后半徑在2秒內從200逐漸變為50。
<circle cx="0" cy="0" r="200" style="stroke: none; fill: #0000ff;">
<animate attributeName="r" from="200" to="50"
begin="4s" dur="2s" repeatCount="2"></animate>
</circle>
1.3、animateColor
控制顏色動畫,animate也可以實現這個效果,所以該屬性目前已被廢棄。
1.4、animateTransform
實現transform變換動畫效果,與css3的transform變換類似。實現平移、旋轉、縮放等效果。
使用語法:
<animateTransform attributeName="transform" type="scale"
from="1.5" to="0"
begin="2s" dur="3s"
repeatCount="indefinite"></animateTransform>
<svg width="320" height="320">
<circle cx="0" cy="0" r="200" style="stroke: none; fill: #0000ff;">
<animateTransform attributeName="transform" begin="4s"
dur="2s" type="scale" from="1.5" to="0"
repeatCount="indefinite"></animateTransform>
</circle>
</svg>
1.5、animateMotion
可以定義動畫路徑,讓SVG各個圖形,沿著指定路徑運動。
使用語法:
<animateMotion
path="M 0 0 L 320 320"
begin="4s" dur="2s"></animateMotion>
eg:繪制一個半徑為10的圓,延遲4秒從左上角運動的右下角。
<svg width="320" height="320">
<circle cx="0" cy="0" r="10" style="stroke: none; fill: #0000ff;">
<animateMotion
path="M 0 0 L 320 320"
begin="4s" dur="2s"
></animateMotion>
</circle>
</svg>
實際制作動畫的時候,動畫太單一不酷,需要同時改變多個屬性時,上邊的四種元素可以互相組合,同類型的動畫也能組合。以上這些元素雖然能夠實現動畫,但是無法動態地添加事件,所以接下來我們就看看 js 如何制作動畫。
上篇文章我們介紹js可以操作path,同樣也可以操作SVG的內置形狀元素,還可以給任意元素添加事件。
給SVG元素添加事件方法與普通元素一樣,可以只用on+事件名 或者addEventListener添加。
eg:使用SVG繪制地一條線,點擊線條地時候改變 x1 ,實現旋轉效果。
<svg width="800" height="800" id="svg">
<line id="line" x1="100" y1="100"
x2="400" y2="300"
stroke="black" stroke-width="5"></line>
</svg>
<script>
window.onload = function(){
var line = document.getElementById("line")
line.onclick = function(){
let start = parseInt(line.getAttribute("x1")),
end=400,dis = start-end
requestAnimationFrame(next)
let count = 0;
function next(){
count++
let a = count/200,cur = Math.abs(start+ dis*a)
line.setAttribute('x1',cur)
if(count<200)requestAnimationFrame(next)
}
}
}
</script>
js制作的SVG動畫,主要利用 requestAnimationFrame 來實現一幀一幀的改變。
我們上述制作的 SVG 圖形、動畫等,運行在低版本IE中,發現SVG只有IE9以上才支持,低版本的并不能支持,為了兼容低版本瀏覽器,可以使用 VML ,VML需要添加額外東西,每個元素需要添加 v:元素,樣式中還需要添加 behavier ,經常用于繪制地圖。由于使用太麻煩,所以我們借助 Raphael.js 庫。
Raphael.js是通過SVG/VML+js實現跨瀏覽器的矢量圖形,在IE瀏覽器中使用VML,非IE瀏覽器使用SVG,類似于jquery,本質還是一個javascript庫,使用簡單,容易上手。
使用之前需要先引入Raphael.js庫文件。cdn的地址為:https://cdn.bootcdn.net/ajax/libs/raphael/2.3.0/raphael.js
3.1、創建畫布
Rapheal有兩種創建畫布的方式:
第一種:瀏覽器窗口上創建畫布
創建語法:
var paper = Raphael(x,y,width,height)
x,y是畫布左上角的坐標,此時畫布的位置是絕對定位,有可能會與其他html元素重疊。width、height是畫布的寬高。
第二種:在一個元素中創建畫布
創建語法:
var paper = Raphael(element, width, height);
element是元素節點本身或ID width、height是畫布的寬度和高度。
3.2、繪制圖形
畫布創建好之后,該對象自帶SVG內置圖形有矩形、圓形、橢圓形。他們的方法分別為:
paper.circle(cx, cy, r); // (cx , cy)圓心坐標 r 半徑
paper.rect(x, y, width, height, r); // (x,y)左上角坐標 width寬度 height高度 r圓角半徑(可選)
paper. ellipse(cx, cy, rx, ry); // (cx , cy)圓心坐標 rx水平半徑 ry垂直半徑
eg:在div中繪制一個圓形,一個橢圓、一個矩形。
<div id="box"></div>
<script>
var paper = Raphael("box",300,300)
paper.circle(150,150,150)
paper.rect(0,0,300,300)
paper.ellipse(150,150,100,150)
</script>
運行結果如下:
除了簡單圖形之外,還可以繪制復雜圖形,如三角形、心型,這時就使用path方法。
使用語法:paper.path(pathString)
pathString是由一個或多個命令組成,每個命令以字母開始,多個參數是由逗號分隔。
eg:繪制一個三角形。
let sj = paper.path("M 0,0 L100,100 L100,0 'Z'")
還可以繪制文字,如果需要換行,使用 \n 。
文字語法:paper.text(x,y,text)
(x,y)是文字坐標,text是要繪制的文字。
3.3、設置屬性
圖形繪制之后,我們通常會添加stroke、fill、stroke-width等讓圖形更美觀,Raphael使用attr給圖形設置屬性。
使用語法:circle.attr({"屬性名","屬性值","屬性名","屬性值",...})
如果只有屬性名沒有屬性值,則是獲取屬性,如果有屬性值,則是設置屬性。
注意:如果只設置一個屬性時,可以省略‘{}’。如:rect.attr('fill','pink')
eg:給上邊的矩形添加邊框和背景色。
<div id="box"></div>
<script>
var paper = Raphael("box",300,300)
let rect = paper.rect(100,100,150,200)
rect.attr({'fill':'red','stroke':'blue','stroke-width':'10'})
</script>
3.4、添加事件
RaphaelJS一般具有以下事件:
click、dblclick、drag、hide、hover、mousedown、mouseout、mouseup、mouseover等以及對應的解除事件,只要在前面加上“un”就可以了(unclick、undblclick)。
使用語法:
obj.click(function(){
//需要操作的內容
})
3.5、添加動畫
animate為指定圖形添加動畫并執行。
使用語法:
obj.animate({
"屬性名1":屬性值1,
"屬性名2":屬性值2,
...
},time,type)
屬性名和屬性值就根據你想要的動畫類型加就ok。
time:動畫所需時間。
type:指動畫緩動類型。常用值有:
eg:點擊矩形,矩形緩緩變大。
<div id="box"></div>
<script>
var paper = Raphael("box",800,500)
let rect = paper.rect(100,100,150,100)
rect.attr({'fill':'red','stroke':'blue','stroke-width':'10'})
rect.attr('fill','pink')
rect.click(function(){
rect.animate({
"width":300,
"height":300
},1000,"bounce")
})
</script>
復制上邊的代碼,分別在各個瀏覽器和低版本IE瀏覽器運行,發現都可以正常運行。SVG的動畫庫挺多了,我們介紹了拉斐爾,有興趣的小伙伴可以自行找找其他庫。
據地圖平臺是字節跳動內部的大數據檢索平臺,每天近萬的字節員工在此查找所需數據。數據地圖通過提供便捷的找數,理解數服務,大大節省了內部數據的溝通和建設成本。
字節的數據可分為端數據和業務數據,這些記錄往往需要通過加工處理才能產生業務價值。數據加工處理的流程一般是讀取原始數據,進行數據清洗,再經過多種計算和存儲,最終匯入指標、報表和數據服務系統。數據血緣描述了數據的來源和去向,以及數據在多個處理過程中的轉換,是組織內使數據發揮價值的重要基礎能力。
數據地圖平臺在 2021 年接入了全鏈路核心元數據,包括但不限于:Hive、Clickhouse、Kafka、BI 報表、BI 數據集、畫像、埋點、MySQL、Abase。這些數據全部要通過數據血緣連接起來,進而可以進行影響分析、內部審計、SLA 保障、歸因分析、理解和查找數據、自動化推薦等操作。
隨著內部數據不斷膨脹,簡單的數據血緣圖譜已經無法滿足萬級表血緣的關系展示。一些突出的問題包括看不清單個表的直接上下游,看不清數據鏈路,整體情況等等。因此需要重構一種更清晰、靈活、便利的方式。下圖簡單展示了優化后的使用效果。
在新版血緣圖譜中,我們可以直接清晰的看到每個表的多層上下游依賴關系,甚至可以直接看到一些特殊場景下用戶關注的表屬性,通過點擊節點高亮查看數據鏈路,更可以看清每層的統計信息。在下文中我們將詳細拆解優化的全過程。
要做出一個能滿足用戶需求的圖產品,首先是要清楚用戶想從圖中獲取什么信息,從而有針對性的將這些信息展示出來。從血緣圖譜的背景本身可以推斷出用戶希望在圖譜中查看表之間的關系,查看關系鏈路,而更多的使用場景待發掘。因此我們對內部重度用戶進行了訪談,整理得出了以下不同用戶角色使用數據血緣圖譜的用戶場景。
結合訪談結果和用戶的日常反饋,數據血緣圖譜的場景按目前用戶的使用頻率從大到小排序依次為:
場景 | 用戶關注 | 場景描述 |
影響分析 | 下游 | 當處于血緣上游的研發同學修改任務前,通過查看自己的下游,通知對應資產或任務的負責人,進行相應的修改,否則會造成嚴重的生產事故。 |
找數理解數 | 上游 | 在找數據時,通過查看一份數據資產的血緣,來更多的了解它的“前世今生”,可以更好的判定當前資產是不是自己需要的,或者是不是值得信賴的。就像了解一個人,可以從他周圍的朋友中得到很多信息一樣,是對這個人“生平”很好的補充。 |
鏈路梳理 | 鏈路 | 事先挑選已知的核心任務,通過血緣關系,自動化的梳理出其所在的核心鏈路。多用于內審和數據治理。 |
歸因分析 | 上游 | 當某一個指標或字段數據/產出時間等出問題時,通過查看血緣上游的任務或資產,排查出造成問題的根因。 |
使用分析 | 下游 | 一個表的下游表越多,使用越頻繁,可以認為價值越大。 |
抽象出幾個主要需求即為:
其實上述需求舊版血緣圖譜都有一定程度上的滿足,我們需要去找出舊版血緣圖譜提供的功能為什么不滿足用戶需求,有哪些問題需要在新版中注意避免。
節點較少,比較清晰
大量節點,查看困難
用戶在使用過程中看重的是查看關系的效率和屬性的完備度,因此在設計優化方案時會盡量從這兩點出發去考慮。
首先是表數據查看的效率問題。看不清表名,無法區分相同前綴的表是用戶痛點之一。首先我們統計了現有表的平均字符數是 47 位,于是調寬了節點讓用戶能更直觀的區分表名。用數據地圖平臺中通用的類型圖表來代替色塊圖例,讓數據類型一目了然。
其次對于數據量大時看不清數據關系的問題,我們需要一個更緊湊清晰的數據呈現方式。通過需求分析和用戶調研,我們了解到用戶關心的是節點所在層級和節點之間的聯系。對于同一層級節點的先后順序,次層級節點之間的關系不是很看重。
說到緊湊的布局方式,自然而然我們就想到了列表。如果能用一個列表來承載層級血緣的節點,用連線來連接不同層級的節點,那么久可以表達節點之間的血緣關系了。當節點較多超出一屏時可以拖動此列滾動條來查看更多節點,連線隨之刷新位置。當層級不滿一屏時整體居中展示,層級過多超過一屏時可以左右滑動查看。這樣在保留層級結構信息的同時最大程度的利用了可視區域,展示出了盡可能多的數據。
新版血緣圖譜支持了點擊任意節點則高亮該節點到主節點的鏈路功能。配合列滾動和連線刷新,不管數據量多大總能看清一整條數據鏈路。
我們還在每列列表頂部增加了層級信息和節點統計,讓用戶能同時查看每個節點細節和節點的整體分布。最終實現效果如下圖:
當用戶想去找數,理解數或做歸因分析時,不僅要了解一個表的上游依賴,更需要理解表的加工邏輯。因此我們在節點的連線上新增了任務信息。當用戶 hover 到連線上后,連線會加粗高亮并彈出任務信息。我們還附上了大數據開發平臺的對應任務鏈接,點擊鏈接即可跳轉到新頁面查看任務邏輯詳情。
在設計分組功能時,采用了每列獨立分組的方式。一般認為用戶會關注有對應分組數據的節點,因此總將有分組的數據放在上面,無分組數據的置底,這樣排序能提升用戶的瀏覽效率。
舊版血緣圖譜的篩選功能是在前端處理的,由于一些性能限制導致篩選后只能顯示部分數據,用戶無法得知符合條件的節點是否已經全部展示。新版血緣圖譜針對這個用戶痛點,將前端篩選改為了服務端篩選,盡量展示全符合要求的數據。每個層級的頂欄對應更新為篩選后的統計信息。同時更新連線,如果篩選后節點之間是有關聯的,也會展示關聯關系和高亮關系鏈路。
不同職能的用戶在不同場景下使用血緣圖譜時關注的節點屬性并不相同,如果血緣圖譜可以直接在圖上顯示用戶當前想關注的表屬性就能幫助用戶更高效的解決問題。于是我們在血緣圖譜上設計了屬性展示功能,用戶可以勾選自己感興趣的屬性直接顯示到圖中。比如下圖中展示了每個節點表熱度和生命周期兩個屬性。
技術選型
在編碼實現之前,我們需要進行技術選型。好的選型往往能讓編碼事半功倍。在做技術選型時,我們會主要考慮實現復雜度、研發周期、可擴展性三個角度。分析整個血緣圖譜的需求:
于是我們結合兩者之長,選用了 React + Canvas 的混合模式來實現血緣圖譜。Canvas 居于底部,僅負責畫連線。React 在上層負責渲染節點響應 hover 等交互。DOM 層疊關系如下:
整個血緣圖譜的初始化流程如下:
實現細節
用這種混合模式的一個挑戰就是 Canvas 和 DOM 的刷新率和同步率。在血緣圖譜中滾動橫向滾動條和每一列的縱向滾動條時 Canvas 要進行及時的刷新以保證連線和節點的相對位置一定。
另一個挑戰是 DOM 節點在大數據量下的性能問題。通常情況下我們認為 Canvas 在大數據量渲染有更好的性能,而萬級的 DOM 節點就會讓用戶在使用中感受到卡頓了。這時候我們想到了按需渲染。 用戶在圖譜可視區域中一屏能看到的節點數量是有限的,高度為 1120 的容器中,一列僅存在至多 30 個節點。如果僅渲染可見的節點,則能保證使用過程的流暢。具體做法是在節點布局時增加以下步驟:
在 React 渲染時更新每列容器的長度,將節點根據坐標絕對定位到正確的位置上。看起來就跟全量渲染的效果一致,渲染效率大幅提升。
然而問題并不止于此。在進行大數據量的縱向滾動時,會發現幀率很低,交互還是不流暢。分析得知是由于列表滾動時會在短時間內進行大量線條重計算和渲染。于是還要在 Canvas 繪制上進行優化。
我們從上圖可以看到在單層節點很多的情況下,主節點與不可見節點的連線可見,但是沒有任何價值,只是加重了用戶對當前節點連線查看的負擔。因此我們對線條也進行了渲染優化,僅當一條連線兩端的節點都在可見范圍中時才渲染連線,在連線的 Tooltip 上增加了來源去向的展示輔助查看。至此我們做到了在復雜情況下的流暢展示血緣數據。
以上就是數據血緣圖譜的整個優化過程。在這個過程中,我總結起來就是在了解用戶訴求的前提下,克制地表達關系圖中的信息,在合適的場景下突出核心的內容。做圖分析產品時不需要拘泥于某種形式,而是真正的從用戶需求出發,為用戶服務。
一站式數據中臺套件,幫助用戶快速完成數據集成、開發、運維、治理、資產、安全等全套數據中臺建設,幫助數據團隊有效的降低工作成本和數據維護成本、挖掘數據價值、為企業決策提供數據支撐。
歡迎加入字節跳動數據平臺官方群,進行數據技術交流、獲取更多內容干貨
點擊 大數據研發治理套件-火山引擎 了解產品詳情
*請認真填寫需求信息,我們會在24小時內與您取得聯系。