D3.js實(shí)現(xiàn)簡潔實(shí)用的動(dòng)態(tài)儀表盤

動(dòng)態(tài)效果圖:

儀表盤效果圖

細(xì)看上面的動(dòng)態(tài)效果圖鹃彻,可以發(fā)現(xiàn):

  • 一個(gè)值變換到一個(gè)新的值時(shí),是一個(gè)漸變的過程妻献;
  • 圓弧末尾有一個(gè)豎線浮声,作為儀表盤的指針,在儀表盤數(shù)值變化時(shí)旋奢,有一個(gè)彈性的動(dòng)畫效果泳挥。

一開始,我是用Echarts來實(shí)現(xiàn)儀表盤至朗,但是它無法滿足上面的兩點(diǎn)需求屉符。所以后來改成用D3.js
D3.js可以完美地實(shí)現(xiàn)圖表的定制,從細(xì)節(jié)上矗钟,完美地滿足我們的需求唆香。

初始化儀表盤

  1. 首先定義一個(gè)svg元素:

    <svg id="myGauge" width="80" height="108" ></svg>
    

    然后,聲明一些變量用于初始化:

    var width=80, 
        height=108,   //svg的高度和寬度吨艇,也可以通過svg的width躬它、height屬性獲取
        innerRadius = 22,
        outerRadius = 30,  //圓弧的內(nèi)外半徑
        arcMin = -Math.PI*2/3,
        arcMax = Math.PI*2/3,  //圓弧的起始角度和終止角度
    
  2. 創(chuàng)建一個(gè) arc 方法,并設(shè)置所有的屬性东涡,除了 endAngle冯吓。在創(chuàng)建圓弧的時(shí)候,傳遞一個(gè)包含 endAngle 屬性的對象到這個(gè)方法疮跑,就可以計(jì)算出一個(gè)給定角度的 SVG path组贺。

    var arc = d3.arc()
        .innerRadius(22)
        .outerRadius(30)
        .startAngle(arcMin)
    

    圓弧角度怎么設(shè)置呢?
    把一個(gè)圓圈對應(yīng)到一個(gè)時(shí)鐘祖娘,那么12點(diǎn)鐘對應(yīng)的角度就是0失尖,順時(shí)針3點(diǎn)鐘的角度是Math.PI/2,逆時(shí)針6點(diǎn)鐘的角度是-Math.PI渐苏。因此-Math.PI*2/3Math.PI*2/3的圓弧形狀如上面的效果圖所示掀潮。更多參考API文檔中的arc.startAngle

  3. 獲取SVG元素琼富,并且轉(zhuǎn)換原點(diǎn)到畫布的中心胧辽,這樣我們在之后創(chuàng)建圓弧時(shí)就不需要再單獨(dú)指定它們的位置了

    var svg = d3.select("#myGauge")
    var g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
    
  4. 添加儀表盤中的文字(標(biāo)題,數(shù)值公黑,單位)

    //添加儀表盤的標(biāo)題
    g.append("text").attr("class", "gauge-title")
        .style("alignment-baseline", "central") //相對父元素對齊方式
        .style("text-anchor", "middle") //文本錨點(diǎn),居中
        .attr("y", -45)   //到中心的距離
        .text("CPU占用率");
    //添加儀表盤顯示的數(shù)值摄咆,因?yàn)橹筮€要更新凡蚜,所以聲明一個(gè)變量
    var valueLabel = g.append("text").attr("class", "gauge-value")
        .style("alignment-baseline", "central") //相對父元素對齊方式
        .style("text-anchor", "middle") //文本錨點(diǎn),居中
        .attr("y", 25)    //到中心的距離
        .text(12.65); 
    //添加儀表盤顯示數(shù)值的單位            
    g.append("text").attr("class", "gauge-unity")
        .style("alignment-baseline", "central") //相對父元素對齊方式
        .style("text-anchor", "middle") //文本錨點(diǎn)吭从,居中
        .attr("y", 40)    //到中心的距離
        .text("%");
    

    D3制作的SVG圖朝蜘,與Echarts繪制的Canvas比起來,很重要的一個(gè)優(yōu)點(diǎn)是涩金,可以用CSS定義SVG的樣式谱醇。比如,此處儀表盤標(biāo)題的樣式如下:

    .gauge-title{
        font-size: 10px;
        fill: #A1A6AD;
    }
    
  5. 添加背景圓弧

    //添加背景圓弧
    var background = g.append("path")
        .datum({endAngle:arcMax})  //傳遞endAngle參數(shù)到arc方法
        .style("fill", "#444851")
        .attr("d", arc);
    
  6. 添加表示百分比的圓弧步做,其中percentage是要表示的百分比副渴,0到1的小數(shù)。

    //計(jì)算圓弧的結(jié)束角度
    var currentAngle = percentage*(arcMax-arcMin) + arcMin
    //添加另一層圓弧全度,用于表示百分比
    var foreground = g.append("path")
        .datum({endAngle:currentAngle})
        .style("fill", "#444851")
        .attr("d", arc);
    
  7. 在圓弧末尾添加一個(gè)指針標(biāo)記

    var tick = g.append("line")
        .attr('class', 'gauge-tick')
        .attr("x1", 0)
        .attr("y1", -innerRadius)
        .attr("x2", 0)
        .attr("y2", -(innerRadius + 12))  //定義line位置煮剧,默認(rèn)是在圓弧正中間,12是指針的長度
        .style("stroke", "#A1A6AD")
        .attr('transform', 'rotate('+ angleToDegree(currentAngle) +')')
    

    rotate中的參數(shù)是度數(shù),Math.PI對應(yīng)180勉盅,因此需要自定義一個(gè)angleToDegree方法把currentAngle轉(zhuǎn)換一下佑颇。

至此,一個(gè)SVG儀表盤就制作出來了草娜,不過是靜止的挑胸,那怎么更新這個(gè)儀表盤呢?

更新儀表盤

需要更新:表示新的百分比的圓辉兹颉茬贵;圓弧下方的數(shù)值。
修改圓弧下方的數(shù)值很簡單:

valueLabel.text(newValue)

更新圓弧則稍麻煩一點(diǎn)议蟆,具體思路是:修改圓弧的endAngle闷沥,以及修改圓弧末尾指針的transform值。
實(shí)現(xiàn)的過程中咐容,需要使用的API:

  1. 更新圓弧舆逃,其中angle為新圓弧的結(jié)束角度。
    //更新圓弧戳粒,并且設(shè)置漸變動(dòng)效
    foreground.transition()
        .duration(750)
        .ease(d3.easeElastic)   //設(shè)置來回彈動(dòng)的效果
        .attrTween("d", arcTween(angle)); 
    
    arcTween方法定義如下路狮。它返回一個(gè)d屬性的補(bǔ)間(漸變)動(dòng)畫方法,使一個(gè)圓弧從當(dāng)前的角度漸變到另一個(gè)新的角度蔚约。
    arcTween(newAngle) {
        let self=this
        return function(d) {
            var interpolate = d3.interpolate(d.endAngle, newAngle); //在兩個(gè)值間找一個(gè)插值
            return function(t) {
                d.endAngle = interpolate(t);    //根據(jù) transition 的時(shí)間 t 計(jì)算插值并賦值給endAngle
                return arc(d); //返回新的“d”屬性值
            };  
        };
    }
    
    這個(gè)方法更詳細(xì)的說明可以參考Arc Tween中的注釋奄妨。
  2. 更新圓弧末尾的指針的原理同上,其中oldAngle是舊圓弧的結(jié)束角度苹祟。
    //更新圓弧末端的指針標(biāo)記砸抛,并且設(shè)置漸變動(dòng)效            
    tick.transition()
        .duration(750)
        .ease(d3.easeElastic)   //設(shè)置來回彈動(dòng)的效果
        .attrTween('transform', function(){ //設(shè)置“transform”屬性的漸變,原理同上面的arcTween方法
            var i = d3.interpolate(angleToDegree(oldAngle), angleToDegree(newAngle));    //取插值
            return function(t) {
                return 'rotate('+ i(t) +')'
            };
        })
    

至此树枫,我們就成功制作了一個(gè)動(dòng)態(tài)刷新的簡介美觀的SVG儀表盤直焙。

結(jié)束

每次使用D3.js都會(huì)忍不住覺得它真是太強(qiáng)大、太有意思了~它就像是一個(gè)百寶箱砂轻,讓我們最大限度地滿足需求奔誓。

參考閱讀:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市搔涝,隨后出現(xiàn)的幾起案子厨喂,更是在濱河造成了極大的恐慌,老刑警劉巖庄呈,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜕煌,死亡現(xiàn)場離奇詭異,居然都是意外死亡诬留,警方通過查閱死者的電腦和手機(jī)幌绍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門颁褂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人傀广,你說我怎么就攤上這事颁独。” “怎么了伪冰?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵誓酒,是天一觀的道長。 經(jīng)常有香客問我贮聂,道長靠柑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任吓懈,我火速辦了婚禮歼冰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘耻警。我一直安慰自己隔嫡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布甘穿。 她就那樣靜靜地躺著腮恩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪温兼。 梳的紋絲不亂的頭發(fā)上秸滴,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音募判,去河邊找鬼荡含。 笑死,一個(gè)胖子當(dāng)著我的面吹牛届垫,可吹牛的內(nèi)容都是我干的释液。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼敦腔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了恨溜?” 一聲冷哼從身側(cè)響起符衔,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎糟袁,沒想到半個(gè)月后判族,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡项戴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年形帮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辩撑,死狀恐怖界斜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情合冀,我是刑警寧澤各薇,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站君躺,受9級(jí)特大地震影響峭判,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜棕叫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一林螃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧俺泣,春花似錦疗认、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贝润,卻和暖如春绊茧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背打掘。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國打工华畏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尊蚁。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓亡笑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親横朋。 傳聞我的和親對象是個(gè)殘疾皇子仑乌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 對集合的操作 關(guān)于d3.attr 一個(gè)可以處理很多情況的函數(shù),當(dāng)只傳入一個(gè)參數(shù)時(shí)琴锭,如果是string晰甚,則返回該屬性...
    陳堅(jiān)生閱讀 2,528評(píng)論 0 2
  • 《肯定自己》 01留學(xué)打工 留學(xué)期間高昂的學(xué)費(fèi)和生活費(fèi)都暗自催促著學(xué)生自己去打工,然而打工的安全與否也成為了父母與...
    墨幽雨閱讀 380評(píng)論 0 1
  • 一群老鼠决帖,深為一只兇狠無比厕九、善于捕鼠的貓所苦。于是地回,老鼠們齊聚一堂扁远,商討如何解決這只討厭的貓俊鱼。有只老鼠的提議立刻引...
    李玉良_閱讀 532評(píng)論 1 1
  • ▲ 這可能是最懂你的小姨媽 1. 塑料姐妹花不止存在于娛樂八卦里并闲,在我們?nèi)粘I钪幸膊簧僖姡B大媽們都緊跟潮流皮获,你...
    樓上的姨閱讀 474評(píng)論 0 0