D3 js實現簡潔實用的動態儀表盤

動態效果圖(動畫開頭有延遲,稍等...):css

儀表盤效果圖

細看上面的動態效果圖,能夠發現:html

  • 一個值變換到一個新的值時,是一個漸變的過程;
  • 圓弧末尾有一個豎線,做爲儀表盤的指針,在儀表盤數值變化時,有一個彈性的動畫效果。

一開始,我是用 Echarts 來實現儀表盤,可是它沒法知足上面的兩點需求。因此後來改爲用D3.jsD3.js能夠完美地實現圖表的定製,從細節上,完美地知足咱們的需求。git

初始化儀表盤

  1. 首先定義一個svg元素:github

    <svg id="myGauge" width="80" height="108" ></svg>
    複製代碼

    而後,聲明一些變量用於初始化:app

    var width=80, 
        height=108,   //svg的高度和寬度,也能夠經過svg的width、height屬性獲取
        innerRadius = 22,
        outerRadius = 30,  //圓弧的內外半徑
        arcMin = -Math.PI*2/3,
        arcMax = Math.PI*2/3,  //圓弧的起始角度和終止角度
    複製代碼
  2. 建立一個 arc 方法,並設置全部的屬性,除了 endAngle。在建立圓弧的時候,傳遞一個包含 endAngle 屬性的對象到這個方法,就能夠計算出一個給定角度的 SVG pathsvg

    var arc = d3.arc()
        .innerRadius(22)
        .outerRadius(30)
        .startAngle(arcMin)
    複製代碼

    圓弧角度怎麼設置呢? 把一個圓圈對應到一個時鐘,那麼12點鐘對應的角度就是0,順時針3點鐘的角度是Math.PI/2,逆時針6點鐘的角度是-Math.PI。所以-Math.PI*2/3Math.PI*2/3的圓弧形狀如上面的效果圖所示。更多參考API文檔中的arc.startAngle動畫

  3. 獲取SVG元素,而且轉換原點到畫布的中心,這樣咱們在以後建立圓弧時就不須要再單獨指定它們的位置了ui

    var svg = d3.select("#myGauge")
    var g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
    複製代碼
  4. 添加儀表盤中的文字(標題,數值,單位)this

    //添加儀表盤的標題
    g.append("text").attr("class", "gauge-title")
        .style("alignment-baseline", "central") //相對父元素對齊方式
        .style("text-anchor", "middle") //文本錨點,居中
        .attr("y", -45)   //到中心的距離
        .text("CPU佔用率");
    //添加儀表盤顯示的數值,由於以後還要更新,因此聲明一個變量
    var valueLabel = g.append("text").attr("class", "gauge-value")
        .style("alignment-baseline", "central") //相對父元素對齊方式
        .style("text-anchor", "middle") //文本錨點,居中
        .attr("y", 25)    //到中心的距離
        .text(12.65); 
    //添加儀表盤顯示數值的單位 
    g.append("text").attr("class", "gauge-unity")
        .style("alignment-baseline", "central") //相對父元素對齊方式
        .style("text-anchor", "middle") //文本錨點,居中
        .attr("y", 40)    //到中心的距離
        .text("%");
    複製代碼

    D3製做的SVG圖,與Echarts繪製的Canvas比起來,很重要的一個優勢是,能夠用CSS定義SVG的樣式。好比,此處儀表盤標題的樣式以下:spa

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

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

    //計算圓弧的結束角度
    var currentAngle = percentage*(arcMax-arcMin) + arcMin
    //添加另外一層圓弧,用於表示百分比
    var foreground = g.append("path")
        .datum({endAngle:currentAngle})
        .style("fill", "#444851")
        .attr("d", arc);
    複製代碼
  7. 在圓弧末尾添加一個指針標記

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

    rotate中的參數是度數,Math.PI對應180,所以須要自定義一個angleToDegree方法把currentAngle轉換一下。

至此,一個SVG儀表盤就製做出來了,不過是靜止的,那怎麼更新這個儀表盤呢?

更新儀表盤

須要更新:表示新的百分比的圓弧;圓弧下方的數值。 修改圓弧下方的數值很簡單:

valueLabel.text(newValue)
複製代碼

更新圓弧則稍麻煩一點,具體思路是:修改圓弧的endAngle,以及修改圓弧末尾指針的transform值。 實現的過程當中,須要使用的API:

  1. 更新圓弧,其中angle爲新圓弧的結束角度。
    //更新圓弧,而且設置漸變更效
    foreground.transition()
        .duration(750)
        .ease(d3.easeElastic)   //設置來回彈動的效果
        .attrTween("d", arcTween(angle)); 
    複製代碼
    arcTween方法定義以下。它返回一個d屬性的補間(漸變)動畫方法,使一個圓弧從當前的角度漸變到另外一個新的角度。
    arcTween(newAngle) {
        let self=this
        return function(d) {
            var interpolate = d3.interpolate(d.endAngle, newAngle); //在兩個值間找一個插值
            return function(t) {
                d.endAngle = interpolate(t);    //根據 transition 的時間 t 計算插值並賦值給endAngle
                return arc(d); //返回新的「d」屬性值
            };  
        };
    }
    複製代碼
    這個方法更詳細的說明能夠參考Arc Tween中的註釋。
  2. 更新圓弧末尾的指針的原理同上,其中oldAngle是舊圓弧的結束角度。
    //更新圓弧末端的指針標記,而且設置漸變更效 
    tick.transition()
        .duration(750)
        .ease(d3.easeElastic)   //設置來回彈動的效果
        .attrTween('transform', function(){ //設置「transform」屬性的漸變,原理同上面的arcTween方法
            var i = d3.interpolate(angleToDegree(oldAngle), angleToDegree(newAngle));    //取插值
            return function(t) {
                return 'rotate('+ i(t) +')'
            };
        })
    複製代碼

至此,咱們就成功製做了一個動態刷新的簡介美觀的SVG儀表盤。

結束

每次使用D3.js都會忍不住以爲它真是太強大、太有意思了~它就像是一個百寶箱,讓咱們最大限度地知足需求。

參考閱讀:

相關文章
相關標籤/搜索