APICloud d3.js 畫餅圖帶動畫效果

學習文獻:http://pkuwwt.github.io/d3-tutorial-cn/adding-elements.html (基礎教學)
https://juejin.im/post/5a81a8946fb9a06334266f05 (講解插值)
https://github.com/pshrmn/notes/blob/master/d3/interpolators.md (解釋插值)
今天要學習總結下d3畫餅圖曹傀,先看效果圖

餅圖.gif

上面是餅圖帶點擊動畫的捺萌,然后中間的數字可以變化毒返。這里面主要用到d3來實現效果铺遂。后面我會貼出我全部的代碼

思路流程

創(chuàng)建SVG--->添加g標簽元素--->數據轉換得到我們需要的數據--->添加path開啟動畫和畫圓--->點擊圓讓其變大--->數字慢慢增長

創(chuàng)建SVG
    var svg = d3.select('#d3Circle')
                .append("svg")
                .attr("width", sellCircleSVGWid)
                .attr("height", sellCircleSVGhei);

.select表示要選擇的函數,append創(chuàng)建SVG书劝,attr用來設置屬性值塑径,我這里設置了寬度和高度。我們創(chuàng)建的SVG是一個矢量圖的格式可無限放大而不失真尘盼。

添加g標簽
  var arcs = svg.selectAll("g")
                .data(piedata)//設置數據集,piedata元素集合
                .enter()
                .append("g")//添加g元素
                .attr("transform", "translate(" + sellCircleSVGWid / 2 + "," + sellCircleSVGhei / 2 + ")");

我通過SVG再創(chuàng)建一個g標簽烦绳,并且讓它移動到圓的中心位置
selectAll表示選中所有的g標簽元素卿捎,但是我們在此之前并沒有創(chuàng)建g標簽元素,所以通過selectAll會返回一個空的集合給我径密。data用于設置數據源午阵,piedata集合里面有多少數據,就會創(chuàng)建多少個g標簽元素給我享扔。enter()表示創(chuàng)建底桂,append表示添加。
注意>迕摺籽懦!! piedata 必須是集合參數(我自己總結出來的,我試過幾次了氛魁,不是集合就不會畫圖出來)
我們最好是把g標簽創(chuàng)建出來暮顺,因為g是用來組合對象的容器。添加到g元素上的變換會應用到其所有的子元素上秀存。添加到g元素的屬性會被其所有的子元素繼承捶码。此外,g元素也可以用來定義復雜的對象应又。

數據轉換得到我們需要的數據
       //創(chuàng)建圓弧生成器
        var arcPath = d3.svg.arc()
                .innerRadius(innerRaidus)
                .outerRadius(outerRadius);
       //創(chuàng)建圓弧生成器
        var arcPath2 = d3.svg.arc()
                .innerRadius(innerRaidus)
                .outerRadius(outerRadius + 5);

        var color = ['#c56b4f', '#e8b63e', '#435fd8'];
        var ptDetail = ["456", "123", "256"];//數據源
        var totalSales = "835";
      //這里數據過濾宙项,拿到需要的數據
        var pie = d3.layout.pie().value(function (d) {
            return d - 0;//將字符串轉為數字
        });
        var dataset = [];//數據集合
        for (var k in ptDetail) {
            dataset.push(ptDetail[k] / totalSales);//算出占用量
        }
        dataset.sort(function (a, b) {//從大到小排序
            return a < b ? 1 : -1
        });
        var piedata = pie(dataset);//拿到需要的數據
        //先定義位置
        var sum = 0;
        piedata.forEach(function (d, i) {//定義自己的顏色乏苦,執(zhí)行實時間等
            d.color = color[i];
            d.position = i;
            d.duration = 2000 * (d.data / d3.sum(dataset));//動畫時長2秒株扛,計算每一個弧形所用動畫時間
            d.delaytime = sum;
            sum += d.duration;
        });

var arcPath = d3.svg.arc().innerRadius(innerRaidus).outerRadius(outerRadius); 創(chuàng)建一個弧生成器,我們把數據傳遞給它汇荐,像這樣arcPath(data)洞就,它就會返回一堆路徑數據給你,這堆數據用于path上面畫圓掀淘。
d3.layout.pie().value 主要用于數據過濾旬蟋,然后內部計算得到開始角度,結束角度


piedata數據轉換后的值.png

這里面的data 是原始的數據革娄,startAngle是開始弧度倾贰,endAngle是結束弧度冕碟。dataset是未進行過濾的數據源

添加path開啟動畫和畫圓
      arcs.append("path")
                .transition()
                .delay(function (d, i) {
                    return d.delaytime;
                })
                .duration(function (d, i) {
                    return d.duration;
                })
                .attrTween("d", function (d, j) {//過度器
                    var i = d3.interpolate(d.startAngle, d.endAngle);
                    return function (t) {
                        d.endAngle = i(t);
                        return arcPath(d);
                    }
                })
                .attr("stroke-width", "2px")
                .attr("fill", function (d, i) {
                    return d.color;
                });

transition()用于開啟動畫的標志,delay()多少時間后開始執(zhí)行匆浙,duration()多少時間內完成安寺,attrTween()過渡器,這個比較難立即了吧首尼,舉一個簡單的例子說明

//下面我用書上的例子來展示
        var svg = d3.select('#d3Circle')
                .append("svg")
                .attr("width", 200)
                .attr("height", 180);
   //定義SVG的寬高
        var svg = d3.select('#d3Circle')
                .append("svg")
                .attr("width", sellCircleSVGWid)
                .attr("height", sellCircleSVGhei);

        var rect = svg.append("rect")
                .attr("fill", "steelblue")
                .attr("x", 10)
                .attr("y", 10)
                .attr("width", 100)
                .attr("height", 30);
        var rectTran = rect.transition()
                .duration(2000)
                .attrTween("width", function (d, i, a) {
                    return function (t) {
                        return Number(a) + t * 300;
                    }
                });

attrTween動畫.gif

所以我們可以理解為挑庶,數字從0到1,慢慢變化的過度软能。繼續(xù)上面的講解
var i = d3.interpolate(d.startAngle, d.endAngle);在d3里面迎捺,interpolate解釋為插值器的意思,我上面貼的鏈接也有對這個進行解釋查排,然后我對它的理解如下


interpolate的理解.png

t的取值為[0,1]凳枝,我們i就是作為一個函數了,如果我們duration時間很長那么通過i(t)得到的數據也會很多跋核,所以我們過度動畫就從0讀到endAngle變化了范舀。arcPath(d)拿到數據函數將其轉換為路徑值,然后賦值給d參數了罪。

點擊圓讓其變大
 var isClick = false
        arcs.on("click", function (d) {//點擊
            d3.select(this).select("path").transition().attr("d", function (d) {
                if (!isClick) {//放大效果
                    isClick = true;
                    return arcPath2(d);
                } else {//還原
                    isClick = false;
                    return arcPath(d);
                }
            });
        });

由于我上面寫了2個arcPath锭环,一個用于點擊后放大的效果的。

數字慢慢增長
 function CusnumDd(el, param) {
        var sum = 0;
        var time = setInterval(function () {
            sum += 1;
            el.innerHTML = sum;
            if (param <= sum) {
                clearInterval(time);
                el.innerHTML = (param);
            }
        }, 100)
    }
全部代碼
<script type="text/javascript">
    $(function () {
        var sellCircleSVGWid = 200;//寬
        var sellCircleSVGhei = 180;//高
        var innerRaidus = 60;
        var outerRadius = 80;

        //定義SVG的寬高
        var svg = d3.select('#d3Circle')
                .append("svg")
                .attr("width", sellCircleSVGWid)
                .attr("height", sellCircleSVGhei);

        /* var rect = svg.append("rect")
         .attr("fill", "steelblue")
         .attr("x", 10)
         .attr("y", 10)
         .attr("width", 100)
         .attr("height", 30);
         var rectTran = rect.transition()
         .duration(2000)
         .attrTween("width", function (d, i, a) {
         return function (t) {
         return Number(a) + t * 300;
         }
         });*/

        //畫圓形圖開始
        var arcPath = d3.svg.arc()
                .innerRadius(innerRaidus)
                .outerRadius(outerRadius);
        //畫圓形圖開始
        var arcPath2 = d3.svg.arc()
                .innerRadius(innerRaidus)
                .outerRadius(outerRadius + 5);

        var color = ['#c56b4f', '#e8b63e', '#435fd8'];
        var ptDetail = ["456", "123", "256"];
        var totalSales = "835";
        var pie = d3.layout.pie().value(function (d) {
            return d - 0;
        });
        var dataset = [];//數據集合
        for (var k in ptDetail) {
            dataset.push(ptDetail[k] / totalSales);
        }
        dataset.sort(function (a, b) {
            return a < b ? 1 : -1
        });//從大到小排序
        var piedata = pie(dataset);//元素集合
        //先定義位置
        var sum = 0;
        piedata.forEach(function (d, i) {
            d.color = color[i];
            d.position = i;
            d.duration = 2000 * (d.data / d3.sum(dataset));//動畫時長2秒泊藕,計算每一個弧形所用動畫時間
            d.delaytime = sum;
            sum += d.duration;
        });

        var arcs = svg.selectAll("g")
                .data(piedata)
                .enter()
                .append("g")
                .attr("transform", "translate(" + sellCircleSVGWid / 2 + "," + sellCircleSVGhei / 2 + ")");
        arcs.append("path")
                .transition()
                .delay(function (d, i) {
                    return d.delaytime;
                })
                .duration(function (d, i) {
                    return d.duration;
                })
                .attrTween("d", function (d, j) {
                    var i = d3.interpolate(d.startAngle, d.endAngle);
                    return function (t) {
                        d.endAngle = i(t);
                        return arcPath(d);
                    }
                })
                .attr("stroke-width", "2px")
                .attr("fill", function (d, i) {
                    return d.color;
                });

        var isClick = false
        arcs.on("click", function (d) {//點擊
            d3.select(this).select("path").transition().attr("d", function (d) {
                if (!isClick) {
                    isClick = true;
                    return arcPath2(d);
                } else {
                    isClick = false;
                    return arcPath(d);
                }
            });
        });


        var s = document.getElementById("number");
        del_ff(s);    //清理空格
        var el = s.firstChild;   //獲得s的第一個子節(jié)點
        CusnumDd(el, 8);


        var a = document.getElementById("dom");
        del_ff(a);
        console.log('獲取a的全部子節(jié)點:')
        console.log(a.childNodes);//獲取a的全部子節(jié)點辅辩;
        console.log('獲取a的父節(jié)點:')
        console.log(a.parentNode); //獲取a的父節(jié)點;
        console.log('獲取a的下一個兄弟節(jié)點:')
        console.log(a.nextSibling);//獲取a的下一個兄弟節(jié)點
        console.log('獲取a的上一個兄弟節(jié)點:')
        console.log(a.previousSibling);//獲取a的上一個兄弟節(jié)點
        console.log('獲取a的第一個子節(jié)點:')
        console.log(a.firstChild);//獲取a的第一個子節(jié)點
        console.log('獲取a的最后一個子節(jié)點:')
        console.log(a.lastChild);//獲取a的最后一個子節(jié)點*/
    });

    function del_ff(elem) {
        var elem_child = elem.childNodes;
        for (var i = 0; i < elem_child.length;) {
            if (elem_child[i].nodeName == "#text" && !/\s/.test(elem_child.nodeValue)) {
                elem.removeChild(elem_child[i])
            }
            else {
                i++;
            }
        }
    }

    /**
     * 功能: 數字滾動顯示
     * @param el 選擇對象
     * @param param 數字參數
     */
    function CusnumDd(el, param) {
        var sum = 0;
        var time = setInterval(function () {
            sum += 1;
            el.innerHTML = sum;
            if (param <= sum) {
                clearInterval(time);
                el.innerHTML = (param);
            }
        }, 100)
    }

</script>
html
<div id="container">
    <div class="circle" id="d3Circle">
        <div id="number">
            <span></span>
        </div>
    </div>

    <div id="dom">
        <div></div>
        <div></div>
        <div></div>

    </div>
</div>
css
<style type="text/css">
        body, html, #allmap {
            width: 100%;
            height: 100%;
            overflow: hidden;
            margin: 0;
            font-family: "微軟雅黑";
        }

        #container {
            width: 100%;
            height: 500px;
            display: flex;
            display: -webkit-flex;
            flex-direction: column;
            align-items: center;
        }

        .circle {
            width: 100%;
            height: 200px;
            display: flex;
            display: -webkit-flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            position: relative;
        }

        #number {
            color: black;
            width: 60px;
            height: 60px;
            line-height: 60px;
            text-align: center;
            position: absolute;
        }

    </style>
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末娃圆,一起剝皮案震驚了整個濱河市玫锋,隨后出現的幾起案子,更是在濱河造成了極大的恐慌讼呢,老刑警劉巖撩鹿,帶你破解...
    沈念sama閱讀 212,222評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異悦屏,居然都是意外死亡节沦,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 90,455評論 3 385
  • 文/潘曉璐 我一進店門础爬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甫贯,“玉大人,你說我怎么就攤上這事看蚜〗懈椋” “怎么了?”我有些...
    開封第一講書人閱讀 157,720評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長渴逻。 經常有香客問我疾党,道長,這世上最難降的妖魔是什么惨奕? 我笑而不...
    開封第一講書人閱讀 56,568評論 1 284
  • 正文 為了忘掉前任仿贬,我火速辦了婚禮,結果婚禮上墓贿,老公的妹妹穿的比我還像新娘茧泪。我一直安慰自己,他們只是感情好聋袋,可當我...
    茶點故事閱讀 65,696評論 6 386
  • 文/花漫 我一把揭開白布队伟。 她就那樣靜靜地躺著,像睡著了一般幽勒。 火紅的嫁衣襯著肌膚如雪嗜侮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,879評論 1 290
  • 那天啥容,我揣著相機與錄音锈颗,去河邊找鬼。 笑死咪惠,一個胖子當著我的面吹牛击吱,可吹牛的內容都是我干的。 我是一名探鬼主播遥昧,決...
    沈念sama閱讀 39,028評論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼覆醇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了炭臭?” 一聲冷哼從身側響起永脓,我...
    開封第一講書人閱讀 37,773評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鞋仍,沒想到半個月后常摧,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 44,220評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡威创,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,550評論 2 327
  • 正文 我和宋清朗相戀三年落午,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片那婉。...
    茶點故事閱讀 38,697評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡板甘,死狀恐怖,靈堂內的尸體忽然破棺而出详炬,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,360評論 4 332
  • 正文 年R本政府宣布呛谜,位于F島的核電站在跳,受9級特大地震影響,放射性物質發(fā)生泄漏隐岛。R本人自食惡果不足惜猫妙,卻給世界環(huán)境...
    茶點故事閱讀 40,002評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望聚凹。 院中可真熱鬧割坠,春花似錦、人聲如沸妒牙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽湘今。三九已至敢朱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間摩瞎,已是汗流浹背拴签。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留旗们,地道東北人蚓哩。 一個月前我還...
    沈念sama閱讀 46,433評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像上渴,于是被迫代替她去往敵國和親杖剪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,587評論 2 350