D3--数据可视化实战总结

d3理解

标签(空格分隔): 未分类


1.绑定数据

  • [x] 定义:通过循环的方式将数据绑定在dom元素上,每个数据对应一个元素,所以这个数据的值就能来设定dom元素的width,height,x,y坐标等,这就表现了数据驱动的思想,同时也是d3的精华所在。

  • [x] 我们绑定的数据通过匿名函数function(d,i)来调用,数据的值就能设置dom元素的属性。

所有的标签都可以进行绑定,对rect,circle,text,我们想要数据来驱动任何元素,那么就用数据绑定该元素,通过attr()设置x,y,width,height,fill,等属性,on()来绑定鼠标事件。

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有些不一样。

4.为什么要在svg上绘图?

svg是可缩放矢量图语言,所以在svg上绘制的几何图形我们可以任意缩放,而不会导致像素模糊,当然也可以body上直接绘制空div,填充的方式,间接表现条形图,不过在通常来讲对前端人员来讲是不可能干的,所以我们一般在svg这个画布上绘制,先append一个div设置width,height,然后再添加rect,circle,svg上的几何图形有,rect,circle,还支持路径自由绘制,何乐而不为呢?

5什么是多值映射?

在绑定数据的过程中,大量的数据会有大量的循环,attr()会写好多次,所以多值映射的目的就是整理代码,可以将attr中的,写到一个attr()中。这就是多值映射,名字高大上,其实不就是简写嘛!!!

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();
})

转载于:https://www.cnblogs.com/caojunjie/p/7553914.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一个可视化实验完整代码。 一、实验目的和要求 1、 使用API函数编制包含各种资源的Windows应用程序; 2、 实现Windows应用程序对键盘与鼠标的响应。 二、实验内容 : 1、问题描述: 创建一个菜单,其中有三个菜单项,分别为“文件”、“计算”和“帮助”,其中,“文件”菜单项包含“打开”、“保存”、“画图”、“退出”等菜单选项;“计算”菜单包含“总和”、“方差”、“均方根”等菜单选项;“帮助”菜单项包含“计算总和帮助”、“计算方差帮助”和“计算均方根帮助”以及“关于”等项 。 若单击“画图”菜单项,则绘出P103图形。 若在用户区内按下鼠标左键,则动态创建一个包括“删除计算总和”、“添加计算平均值”和“修改计算均方差”三个菜单项的弹出式菜单,由此菜单控制“计算”菜单中菜单项删除、添加与修改。(要求新的弹出式菜单开始时不可用,按下右键后变为可用。) 单击“修改计算均方差”菜单项后,“计算”菜单下的“计算均方差”项改为“线性拟合”,单击“添加计算平均值”菜单项后,“计算”菜单中添加上了“计算平均值”菜单项 。 将光标设定为自己名字中的某个字、图标设定为自己名字中的另一个字。 2、应用程序中所用到的资源、消息,简介主要函数的功能; 3、程序实现 4、操作结果

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值