日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
前端高級(jí)之路:寫(xiě)一個(gè)高逼格可視化“圓環(huán)

圖1 所示是一些我們平時(shí)比較常見(jiàn)的一些圓環(huán)(圓?。┬Ч?。雖然圖形的主體構(gòu)成都是圓弧,但不同效果在信息傳達(dá)的功能上卻略有差異。如:

創(chuàng)新互聯(lián)建站專注于大通企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站建設(shè),商城網(wǎng)站建設(shè)。大通網(wǎng)站建設(shè)公司,為大通等地區(qū)提供建站服務(wù)。全流程按需規(guī)劃網(wǎng)站,專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)建站專業(yè)和態(tài)度為您提供的服務(wù)

  • 閉合的圓環(huán)可以表示流程 “進(jìn)度” 的概念
  • 非閉合圓環(huán)一般用于狀態(tài)量(標(biāo)量)的展示,一般也稱為 “儀表盤(pán)” 效果
  • 不同的色相可用于標(biāo)識(shí)狀態(tài)量的狀態(tài)區(qū)間(如:低危-中危-高危 區(qū)間的標(biāo)識(shí)可以使用三種顏色的構(gòu)成的過(guò)渡效果進(jìn)行表達(dá))

為了更加方便、完善地解決我們?cè)跇I(yè)務(wù)開(kāi)發(fā)時(shí)的具體需要,可以對(duì)這些風(fēng)格、樣式進(jìn)行一定分析、抽象,總結(jié)出一個(gè)通用組件需要具備的能力,如:

  • 顏色、漸變可配(支持傳入單一色值或顏色序列)
  • 圓弧寬度可調(diào)(內(nèi)、外半徑大小可配置)
  • 圓弧夾角可調(diào)(開(kāi)始角度、截止角度可配置)
  • 圓弧端點(diǎn)造型可選(可切換平角/半圓造型
  • 文案效果可調(diào)(字號(hào)、字體、顏色等)

下面,我們著手于實(shí)現(xiàn)這樣一個(gè)功能全面、業(yè)務(wù)通用性較強(qiáng)的圓環(huán)組件。

1. 圓環(huán)的造型
繪制圓環(huán)造型的第一步,需要先繪制圓環(huán)圖表構(gòu)成要素,即一段一段的圓弧。而對(duì)于像下圖中這樣的兩種倒角效果(黃色部分圓弧兩端的樣式),既可以是直角,也可以是半圓。

因此,我們需要實(shí)現(xiàn)一個(gè)通用的方法來(lái)繪制圓弧,提供兩種倒角風(fēng)格給用戶。

1.1 前景圓弧的繪制

圓弧繪制的思路如上圖所示,按先后順序大致分為幾個(gè)步驟:

(1)繪制圓弧起始端的半圓輪廓

(2)繪制圓弧的外邊緣輪廓

(3)繪制圓弧終止端的半圓輪廓

(4)繪制圓弧的內(nèi)邊緣輪廓

(5)閉合輪廓并填充色彩

注:由于 canvas 繪制圓弧的方法默認(rèn)是順時(shí)針?lè)较?,因而我們的繪圖步驟也是沿著順時(shí)針?lè)较?/p>

以下是一些姿勢(shì)要領(lǐng):

1.1.1 端點(diǎn)坐標(biāo)的計(jì)算
在繪制端點(diǎn)半圓之前我們需要端點(diǎn)的位置坐標(biāo),以其實(shí)端為例,根據(jù)圓環(huán)的半徑(內(nèi)外徑的均值,即圓弧中線的半徑)和起始端點(diǎn)的角度如何計(jì)算圓上一點(diǎn)的坐標(biāo):

 
 
 
 
  1. // 計(jì)算圓弧上某點(diǎn)的坐標(biāo)
  2. // originX, originY - 圓心的坐標(biāo)
  3. // radius - 圓環(huán)半徑,等于圓環(huán)內(nèi)、外徑的平均值,也即圓弧中線的半徑
  4. // alpha - 弧度
  5. function calcPosition(originX, originY, radius, alpha) {
  6.   return [
  7.     radius * Math.cos(alpha) + originX,
  8.     radius * Math.sin(alpha) + originY,
  9.   ];
  10. }

1.1.2 端點(diǎn)半圓的起止角度

在 canvas 中繪制一個(gè) arc,需要知道其起始角度和終止角度。由于 canvas 繪制默認(rèn)方向?yàn)槠聊豁槙r(shí)針?lè)较颍ㄆ聊?Z軸 的左手螺旋方向),從上面的示意圖中可以看出:

起始端半圓弧度范圍 - [radianStart - Math.PI, radianStart]

終止端半圓弧度范圍 - [radianEnd, radianEnd + Math.PI]

1.1.3 繪制半圓
有了端點(diǎn)坐標(biāo)和起止角度,便可以繪制端點(diǎn)的半圓:

 
 
 
 
  1. // 以起始端的半圓倒角為例
  2. myCanvas.context.arc(
  3.   x,
  4.   y,
  5.   (radiusOutter - radiusInner) / 2,     // 小圓半徑,等于圓環(huán)線寬的一半
  6.   radianStart - Math.PI,
  7.   radianStart
  8. );

直角倒角風(fēng)格的繪制與半圓倒角圓弧的繪制步驟基本相同,主要差別在于不用繪制圓弧兩個(gè)端點(diǎn)的小半圓,改成繪制直線。背景圓弧的繪制也與前景圓弧方法一致。

2. Canvas 實(shí)現(xiàn)錐形漸變
上面的步驟可以繪制出圓弧的輪廓,要達(dá)到 圖1 那樣的視覺(jué)效果,我們需要給前面繪制出來(lái)的輪廓填充圖像。

沿著圓周方向的漸變,因?yàn)槠鋱D像形似圓錐體的俯瞰效果,俗稱錐形漸變:

眾所周知,CSS 中有一個(gè)名為 conic-gradient 的屬性直接支持錐形漸變,而 HTML Canvas 的原生 API 目前還沒(méi)有類似的能力。那么,我們?nèi)绾卧?canvas 中繪制出這樣的圖像呢?

下面我們講下大致的原理:

(1)對(duì)用戶傳入的顏色進(jìn)行插值,得到一個(gè)顏色序列。

這里,我們直接使用 canvas 原生的 createLinearGradient 方法,在離屏 canvas 中繪制一個(gè) 1px 的線性漸變效果,圖像寬度正好是我們要插值的數(shù)量,漸變插值的結(jié)果也就是 canvas 上對(duì)應(yīng)像素位置的色值。

顏色插值(漸變?nèi)∩┐a實(shí)現(xiàn)如下:

 
 
 
 
  1. // 用于實(shí)現(xiàn)顏色插值的工具類
  2. export default class ColorInterpolate {
  3.   // 參數(shù)01: stops - 為要插值的顏色序列,數(shù)據(jù)格式形如:[[0, 'red'], [0.5, 'green'], [1.0, 'yellow']]
  4.   // 參數(shù)02: segment - 插值段落數(shù),即插值結(jié)果的顏色值的數(shù)量
  5.   constructor(stops = [], segment = 100) {
  6.     // 構(gòu)建離屏 canvas
  7.     const canvas = document.createElement('canvas');
  8.     canvas.width = segment;
  9.     canvas.height = 1;
  10.     this.ctx = canvas.getContext('2d');
  11.     // 繪制線性漸變
  12.     const gradient = this.ctx.createLinearGradient(0, 0, segment, 0);
  13.     for (let [offset, color] of stops) {
  14.       gradient.addColorStop(offset, color);
  15.     }
  16.     this.ctx.fillStyle = gradient;
  17.     this.ctx.fillRect(0, 0, segment, 1);
  18.   }
  19.   // 根據(jù)位置偏移量獲取插值后的色值
  20.   getColor(offset) {
  21.     const imgData = this.ctx.getImageData(offset, 0, 1, 1);
  22.     return `rgba(${imgData.data.slice(0, 3).join(',')}, ${imgData.data[3] / 255})`;
  23.   }
  24. }

(2)如下圖所示,我們可以把漸變的圖像看成是由足夠多填充了單個(gè)色值的小 “扇面” 拼接而成。

按照這樣的思路,我們只需要遍歷上面色彩插值得到的各個(gè)顏色,然后逐個(gè)繪制小扇面,便可得到一個(gè)錐形漸變圖像。

為此我們封裝了一個(gè)名為 createConicalGradient 的方法,其使用習(xí)慣與 canvas 原生的 createLinearGradient 和 createRadialGradient 方法相似。具體代碼見(jiàn) 我的 Github(覺(jué)得有用的童鞋可以 star 一下)。

3. 過(guò)渡動(dòng)畫(huà)
3.1 圓弧的過(guò)渡
在數(shù)值發(fā)生改變時(shí),我們的圖表需要一個(gè)能夠跟隨數(shù)據(jù)改變的過(guò)渡動(dòng)畫(huà)效果,對(duì)于 canvas 而言,便是清除舊圖像然后繪制新一幀圖像。這里有一些方法包裝上的技巧:

 
 
 
 
  1. // 注:偽代碼,真實(shí)場(chǎng)景建議 OOP 方式包裝為工具類
  2. let _animTick = null;
  3. let _animFrames = null;
  4. let _frameData = null;
  5. let _animDiff = null;
  6. // 動(dòng)畫(huà)方法
  7. function _animate(duration) {
  8.   if (_animTick === null) {
  9.     // 根據(jù)動(dòng)畫(huà)時(shí)長(zhǎng) duration 計(jì)算整個(gè)動(dòng)畫(huà)一共需要多少幀(以 60fps 計(jì)算)
  10.     _animFrames = Math.round((duration / 1e3) * 60);
  11.     // 相鄰兩幀動(dòng)畫(huà)的數(shù)據(jù)變化
  12.     _animDiff = _calcAnimDiff(_animFrames);
  13.     // 動(dòng)畫(huà)幀數(shù)標(biāo)識(shí)
  14.     _animTick = 0;
  15.   }
  16.   // 當(dāng)前幀的數(shù)據(jù)值
  17.   _frameData = _caclCurentData(_animDiff, _animTick);
  18.   _renderFrame(_frameData);
  19.   if (_animTick !== null && _animTick < _animFrames) {
  20.     // 繼續(xù)執(zhí)行動(dòng)畫(huà)
  21.     window.requestAnimationFrame(() => {
  22.       _animate();
  23.       _animTick += 1;
  24.     });
  25.   } else {
  26.     // 動(dòng)畫(huà)結(jié)束
  27.     _renderFrame(_frameData);
  28.     _animTick = null;
  29.   }
  30. }
  31. // 繪制當(dāng)前幀
  32. function _renderFrame(data) {
  33.   // ...
  34. }
  35. // 計(jì)算動(dòng)畫(huà)相鄰幀的數(shù)據(jù)差異
  36. function _calcAnimDiff() {
  37.   // ...
  38. }
  39. // 根據(jù)兩幀數(shù)據(jù)差計(jì)算當(dāng)前幀
  40. function _caclCurentData() {
  41.   // ...
  42. }

3.2 兩種動(dòng)畫(huà)模式
在過(guò)渡動(dòng)畫(huà)執(zhí)行的過(guò)程中,需要考慮兩種不同的模式:一種是漸變圖像不變化,僅是圓弧的輪廓從舊狀態(tài)變化到新?tīng)顟B(tài);一種是漸變圖像的夾角范圍跟隨輪廓的大小改變。

這兩種模式其實(shí)都有一定意義:前者可以使用不同顏色代表數(shù)值的不同狀態(tài);后者僅僅是將漸變的顏色看成一種裝飾效果。

4. 結(jié)果演示
比較關(guān)鍵的原理都介紹完了,最后展示一下我們封裝的圖表組件的效果(右側(cè) GUI 部分是我們自研的設(shè)計(jì)引擎的編輯效果):


當(dāng)前標(biāo)題:前端高級(jí)之路:寫(xiě)一個(gè)高逼格可視化“圓環(huán)
當(dāng)前地址:http://www.5511xx.com/article/dhshioe.html