D3--數據可視化實戰總結

d3理解

標籤(空格分隔): 未分類css


1.綁定數據

  • [x] 定義:經過循環的方式將數據綁定在dom元素上,每一個數據對應一個元素,因此這個數據的值就能來設定dom元素的width,height,x,y座標等,這就表現了數據驅動的思想,同時也是d3的精華所在。html

  • [x] 咱們綁定的數據經過匿名函數function(d,i)來調用,數據的值就能設置dom元素的屬性。前端

全部的標籤均可以進行綁定,對rect,circle,text,咱們想要數據來驅動任何元素,那麼就用數據綁定該元素,經過attr()設置x,y,width,height,fill,等屬性,on()來綁定鼠標事件。jquery

svg.selectAll("rect")
        .data(dataset)  data方法後的語句都會循環,循環次數爲數據個數
        .enter()
        .append("rect")
        .attr("x",function(d,i){
            return xscale(i);
        })
        .attr("y",function(d){
            return (h-yscale(d));
        })
        .attr("height",function(d){
            return yscale(d);
        })
        .attr("width",xscale.rangeBand())
        .attr("fill",function(d){
            return "rgb(0, 0, " + Math.round(d * 10) + ")";
        })
        .on("click",function(d){  經過on來事件綁定,記住事件綁定種類就能夠了
            console.log(d);
        })
        .on("mouseover",function(){
            d3.select(this)
                .attr("fill","orange")
        })
        .on("mouseout",function(d){
            d3.select(this)
                .transition()
                .duration(250)
                .attr("fill","rgb(0,0,"+d*10+")")
        })
        .on("click",function(){
            sortBar();
        })

2.數軸

  • [x] 數軸也是d3中的一個對象,先定義一個數軸,而後將這個數軸放到svg中,通常是放在透明g元素中。數軸在定義的時候要講比例尺映射上去,這樣當比例尺改變的時候,咱們只要call()一次就行了,在svg對象上,經過call()方法來調用數軸
  • [x] 在事件監聽器後,從新更新數軸,要放到最後
/*座標軸聲生成*/
    var xaxis=d3.svg.axis()
                .scale(xscale)
                .orient("buttom")
                .ticks(10)
                // .tickFormat(formator);
    var yaxis=d3.svg.axis()
                .scale(yscale)
                .orient("left")
                .ticks(10);
    /*g是group的意思,跟html中div做用同樣*/
    svg.append("g")
        .attr("class","x axis")
        .attr("transform", "translate(0," + (h - padding) + ")")
        .call(xaxis);
    svg.append("g")
        .attr("class","y axis")
        .attr("transform","translate("+(padding)+",0)")
        .call(yaxis);
  • [x] 給座標軸添加css屬性
    座標軸自己是由path,line,text元素組成的,因此咱們能夠添加類的方式來設定css屬性樣式,固然屬性名也只能用svg中的屬性名。
<style type="text/css">
    .axis path,
    .axis line{
        fill: none;
        stroke: blue;
        stroke-width:2;
        shape-rendering: crispEdges;
    }
    .axis text{
        font-size: 11px;
        fill: grey;

    }
</style>
  • [x] 刻度數值格式化
var formatAsPersontage=d3.format(".1%")
xaxis.ticketFormat(formatAsPersontage)

3. attr() 與style()

attr()設置svg標籤元素的屬性
    如fill stroke stroke-width等  與一般 的js中css屬性並不同
    
    style()方法來設置css屬性。 至關於在css類上添加一行
    
    .classed("bar",true)   d3中快速的添加刪除類
    .classed("bar",false)

二者的區別在於數組

<div class="rec" style="color:"red";"> </div>

很明顯,屬性與style是一個級別的,style是做用在二級變量上的。
d3中常常在svg操做,有些屬性只能是svg的,與html有些不同。app

4.爲何要在svg上繪圖?

svg是可縮放矢量圖語言,因此在svg上繪製的幾何圖形咱們能夠任意縮放,而不會致使像素模糊,固然也能夠body上直接繪製空div,填充的方式,間接表現條形圖,不過在一般來說對前端人員來說是不可能幹的,因此咱們通常在svg這個畫布上繪製,先append一個div設置width,height,而後再添加rect,circle,svg上的幾何圖形有,rect,circle,還支持路徑自由繪製,何樂而不爲呢?dom

5什麼是多值映射?

在綁定數據的過程當中,大量的數據會有大量的循環,attr()會寫好屢次,因此多值映射的目的就是整理代碼,能夠將attr中的,寫到一個attr()中。這就是多值映射,名字高大上,其實不就是簡寫嘛!!!svg

6如何實現動態縮放?

咱們的數據量隨時有可能改變,那麼當數據量改變的時候難道要從新設置每一個bar的width及x,y座標嗎?顯然是不可能的
解決方法就是函數

.attr("x「,function(d,i){
    return i*(w/dataset.length);
     })
.attr("width",function(){
    return w/dataset.length-padding;
    
    })

出發點就是將svg畫布的寬度與i關聯起來動畫

7如何將圖形元素標記數值?

其實很簡單,既然數據能綁定在rect,circle上,那麼數據也能綁定在text元素上了,再向svg中append()text元素就行,並設定text元素座標,而後用text()方法打印出來。

svg.selectAll("text")
        .data(dataset)
        .enter()
        .append("text")
        .text(function(d){
            return d;
        })
        .attr("x",function(d,i){
            return xscale(i);
        })
        .attr("y",function(d){
            return (h-yscale(d)+12);
        })
        .attr("font-size","10px")
        .attr("fill","white")
        .style("pointer-events","none")

8比例尺

其實比例尺就是從一個定義域映射到另外一個值域而已,這個值域就是咱們本身所設定的範圍.由於是範圍,因此參數是[]中括號形式。

//ordinal是一個序數比例尺,會根據數據集數量來平均分段,且保存了每段的寬度,
var xscale=d3.scale.ordinal()
            .domain(d3.range(dataset.length))
            .rangeRoundBands([0,w],0.1);
    //eg.   .nice()
        /*將y值映射到0-100*/
//當數據類型不是點集的形式,max()下不用嵌套匿名函數
    var yscale=d3.scale.linear()
            .domain([0,d3.max(dataset,function(d){
                return d;
            })])
            .range([5,h]);

在linear比例尺中,有幾個簡便方法。

.nice()  將值域取整
.rangeRound() 取整
.clamp()  將值域壓縮,當定義域超出範圍

用法,直接連接在比例尺後邊,如上邊標註eg

其餘比例尺,

sqrt  平方根
pow   冪函數
log   對數
quantize   對數據分類狀況
ordinal    序數比例尺  意思就是離散的值
d3.scale.category10()    預設好的輸出10到20中顏色比例尺
d3.time.scale()    日期比例尺
  • [ ] 序數比例尺的好處
//在咱們映射到值域的時候
//既能夠用range,也可rangBands,會自動分檔,還可rangeRoundBands()分檔加取整
var xScale = d3.scale.ordinal()
                .domain(d3.range(dataset.length))
                .rangeRoundBands([0, w], 0.05);

這樣在bar中求寬度時,能夠直接調用比例尺下求出來的。

.attr("width", xScale.rangeBand())

9事件監聽器

d3.select("button")
        .on("click",function(){
        
        })

10過渡函數transition()

svg.selectAll("circle")
    .data(dataset)
    .transition()     過渡函數
    .duration(1000)   持續事件
    .ease("linear")   緩動函數
    .each("start",function(){
       d3.select(this)
        // .transition()
        // .duration(200)  //在on方法中不能再有新的過分效果,只能執行當即變換的,不然會覆蓋掉前邊的
        .attr("fill","magenta")
        .attr("r",3)
})
//同時也能夠有延遲函數
        .delay(function(d,i){
            return i*100;
        })

幾種緩動效果:cubic-in -out 默認效果
linear
circle
elatic
bounce

11.each() 在過渡開始或者結束設定效果

在該方法中能夠在開始或者結束時設定新的效果,可是若是是start不能再使用過渡函數transition(),由於d3的設計中新的過渡會覆蓋掉就的過渡,在外層已經有了一層transition,若是在each內部,再設定一個transition那麼就會覆蓋外部的transition,外部的一切attr所設定的都會失效。d3是有意這樣作的,不想jquery咱們必需要等到一個動畫結束才能夠操做,很煩人。因此只能在start內部使用變換,不能過渡。
參數是end那麼就能夠,爲何?由於這個元素上一層的過渡已經完成了,咱們即便在內部再有transition也無所謂。

//只接受兩個參數
each("start",function(){})  each("end",function(){})

.each("start",function(){
       d3.select(this)
        // .transition()
        // .duration(200)  //在on方法中不能再有新的過分效果,只能執行當即變換的,不然會覆蓋掉前邊的
        .attr("fill","magenta")
        .attr("r",3)
})

12剪切蒙版 ClipPath

剪切蒙版至關於ps中的蒙版,只有落在蒙版內部的元素纔會顯示出來,ClipPath與g元素同樣也是沒有元素,咱們在內部定義可見元素做爲蒙版的畫布大小。

//在html效果
<ClipPath id="chartarea">
    <rect x="30" y="30" width="200" height="300"></rect>
</ClipPath>
/*定義蒙版*/
    svg.append("clipPath")
        .attr("id","chartarea")
        .append("rect")
        .attr("x",padding)
        .attr("y",0)
        .attr("width",w-padding)
        .attr("height",h-padding);

svg.append("g")   //將全部的circle添加到g元素中,並設置id之後方便引用
        .attr("id","circles")
        .attr("clip-path","url(#chartarea)")//引用蒙版 注意引用屬性名
        .selectAll("circle")
        .data(dataset)
        .enter()
        .append("circle")
        ...

13 bars.enter()與bars.exit()再理解

增長元素狀況:當咱們經過data方法對空佔位進行綁定後,

var bars=svg.selectAll("rect")
                        .data(dataset,function(d){
                            return d.key;
                        })
返回一個更新元素集,在內部保存着加入和退出子元素集的引用

bars.enter()會一一比較數據的個數與dom元素的個數,由於enter對應的是添加狀況,因此會發現數據的個數比dom元素的個數多,咱們就會拿到加入元素集的引用,而後再.append("rect")

//每次enter只會有一個佔位符
            bars.enter()  
                .append("rect")
                .attr("x",w)//放到最後
                .attr("y",function(d){
                    return h-yscale(d);
                })
                .attr("width",function(d){
                    return xscale.rangeBand();
                })
                .attr("height",function(d){
                    return yscale(d);
                })
            
            bars.transition()   //在從新更新位置
                // .delay(function(d,i){//每一個加載數據延遲
                //  return i/dataset.length*1000;
                // })
                .duration(500)
                // .ease("linear")
                .attr("x",function(d,i){
                    return xscale(i);
                })

bars.exit()一樣也是會比較,以後咱們拿到退出元素集的dom元素的引用

bars.transition()   //沒有退出元素的引用
                // .delay(function(d,i){//每一個加載數據延遲
                //  return i/dataset.length*1000;
                // })
                .duration(500)
                // .ease("linear")
                .attr("x",function(d,i){
                    return xscale(i);
                })
                .attr("y",function(d){
                    return (h-yscale(d.value));
                })
                .attr("height",function(d){
                    return yscale(d.value);
                })
                .attr("width",xscale.rangeBand())
                .attr("fill",function(d){
                    return "rgb(0, 0, " + Math.round(d.value * 10) + ")";
                });
            bars.exit()     //退出元素的引用
                .transition()
                .duration(500)
                .attr("x",-xscale.rangeBand())
                .remove();

14爲何須要鍵綁定?

data.shit()刪除的是第一個數據,當咱們更新dom元素會發現第一個
rect變成了第二個數值,咱們明明想把第一個連同dom元素一塊刪除掉的,這也就是dom元素的順序並無和數據的順序實現一一綁定,這也就是鍵綁定存在的緣由。
怎麼操做?
其實很簡單,綁定數據的時候將key也綁定上去

//dataset is now an array of objects.
//Each object has a 'key' and a 'value'.
var dataset = [ { key: 0, value: 5 },
                { key: 1, value: 10 },  
                { key: 2, value: 13 },
                { key: 3, value: 19 },
                { key: 4, value: 21 },
                { key: 5, value: 25 },
                { key: 6, value: 22 },
                { key: 7, value: 18 }]
var key = function(d) {
                return d.key;
            };
//Bind data with custom key function
            svg.selectAll("rect")
               .data(dataset, key)  
               .enter()
               ...
//Bind data with custom key function
            svg.selectAll("text")
               .data(dataset, key)  
               .enter()
               ...

15綁定事件監聽器

事件監聽器種類有:click mouseover mouseout

pointer-events:none   令監聽器失效

通常有兩種策略

  • 直接經過attr()或者styel()改變
  • 經過類改變,在類中設定好css樣式
on("hover",function(d,i){  肯定事件
    d3.select(this)    選擇元素
        .attr("fill","orange")   要作哪些改變
        .transiton()

})

sort函數會將元素綁定的值進行排序成一個新數組。

sort(function(a,b){return d3.ascending(a,b)})
  • [ ] 升序與降序問題:在點擊後,鼠標移動的地方,過渡會中止,由於咱們在hover上設置了一個過渡,這個過渡覆蓋掉了升序或降序中的過渡。

16html提示條

策略:body中設置好一個div,不可見,當鼠標hover則改成可見,移走再不可見。classed()方法 添加刪除class屬性

.on("click",function(d){
            console.log(d);
        })
.on("mouseover",function(d){
    var xposition=parseFloat(d3.select(this).attr("x")+xscale.rangeBand/2);
    var yposition=parseFloat(d3.select(this).attr("y")/2+h/2);

d3.select("#tooltip")
    .transition()
    .duration(500)
    .style("left",xposition+"px")
    .style("top",yposition+"px")
    .select("#value")
    .text(d)
d3.select("#tooltip").classed("hidden",false);

})
.on("mouseout",function(){
    d3.select("#tooltip").classed("hidden",true);  
})
.on("click",function(){
    sortBar();
})
相關文章
相關標籤/搜索