【D3.js数据可视化系列教程】(二十二)--交互图表之提示条

这里介绍三种典型的提示条方案:

  1. 默认

element.append("title")// 追加默认格式的提示
.text(function(d){// 追加提示文字
    return "提示文字:"+d.value;
});

  2. svg

.on("mouseover",function(d){
  //(1)取得提示显示的位置
  var xPosition=parseFloat(d3.select(this).attr("x"))+xScale.rangeBand()/2;
  var yPosition=parseFloat(d3.select(this).attr("y"))+24;

  //(2)创建提示条SVG
  svg.append("text")
    .attr("id","tooltip")//设置id便于移除提示
    .attr("x",xPosition)
    .attr("y",yPosition)
    .attr("text-anchor","middle")
    .attr("font-family","sans-setif")
    .attr("font-size","11px")
    .attr("font-weight","bold")
    .attr("fill","white")
    .text(d.value);
 })
 //(3)移除提示条SVG
 .on("mouseout",function(){
    d3.select("#tooltip").remove();
 })

  3. div

  • (1) 创建div提示层

    <div id="tooltip" class="hildden">
    <p><strong>提示:</strong></p>
    <p><span id="value">100</span>%</p>
    v>
    
  • (2)给提示条加上样式

#tooltip {
  position:absolute;
  width:200px;
  height:auto;
  padding:10px;
  background-color:white;

  -webkit-border-radius:10px;
  -moz-border-radius:10px;
  border-radius:10px;

  -webkit-box-shadow:4px 4px 10px rgba(0,0,0,0.4);
  -moz-box-shadow:4px 4px 10px rgba(0,0,0,0.4);
  box-shadow:4px 4px 10px rgba(0,0,0,0.4);

  pointer-events:none;
}

#tooltip.hidden{
  display:none;
}

#tooltip p{
  margin:0;
  font-family:sans-serif;
  font-size:16px;
  line-height:20px;
}
  • (3)更新提示条的值和位置
.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")
    .style("left",xPosition+"px")
    .style("top",yPosition+"px")
    .select("#value")
    .text(d.value);
})
//移除提示条SVG
.on("mouseout",function(){
  //(4)添加隐藏类
  d3.select("#tooltip").classed("hidden",true);//ID 选择的语法:"#tooltip"
}) ;
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>testD3-18-update.html</title>
        <script type="text/javascript" src="http://localhost:8080/spring/js/d3.v3.js"></script>
    <style type="text/css">
    /* 鼠标悬停时变色*/
    rect:hover{
    fill :red;
    }
    /* 过渡效果*/
    rect{
    -moz-transiton:all 0.3s;
    -o-transiton:all 0.3s;
    -webkit-transition:all 0.3s;
    transition:all 0.3s
    }
    /*(2)给提示条加上样式*/
    #tooltip {
        position:absolute;
        width:200px;
        height:auto;
        padding:10px;
        background-color:white;

        -webkit-border-radius:10px;
        -moz-border-radius:10px;
        border-radius:10px;

        -webkit-box-shadow:4px 4px 10px rgba(0,0,0,0.4);
        -moz-box-shadow:4px 4px 10px rgba(0,0,0,0.4);
        box-shadow:4px 4px 10px rgba(0,0,0,0.4);

        pointer-events:none;
    }

    #tooltip.hidden{
        display:none;
    }

    #tooltip p{
        margin:0;
        font-family:sans-serif;
        font-size:16px;
        line-height:20px;
    }

    </style>
    </head>
    <body>
    <button>单击更新</button>
    <br>
    <p id="remove">单击删除</p>
    <p id="add">单击添加</p>
    <!-- (1)创建div提示层 -->
    <div id="tooltip" class="hildden">
        <p><strong>提示:</strong></p>
        <p><span id="value">100</span>%</p>
    </div>
    <br>
        <script type="text/javascript">
//键值对数据集
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},
{key:8,value:15},
{key:9,value:13},
{key:10,value:11},
{key:11,value:12},
{key:12,value:15},
{key:13,value:20},
{key:14,value:18},
{key:15,value:17},
{key:16,value:16},
{key:17,value:18},
{key:18,value:23},
{key:19,value:25}];

//设置SVG的高宽
var w=600;
var h=250; 
var barPadding = 1;
//定义序数比例尺
var xScale=d3.scale.ordinal()//序数比例尺
    .domain(d3.range(dataset.length))  
    .rangeRoundBands([0,w],0.05); 

// 更新数据引用,包含下面所有关于要使用到d.value的地方             
var yScale=d3.scale.linear()//y仍然是线性比例尺
    .domain([0,d3.max(dataset,function(d){
        return d.value;
    })])
    .range([0,h]);  

// 定义键函数(简洁),以备数据绑定到元素的时候使用
//把所有.data(dataset)改成.data(dataset,key)
var key=function(d){
    return d.key;
};

//值函数 
var value=function(d){
    return d.value;
};

//条排序函数
var sortOrders=false;
var sortBars=function(){
    sortOrders=!sortOrders;//(3)每点击一次排序方向改变
    svg.selectAll("rect")
    .sort(function(a,b){
        if(sortOrders){
            //对数据集升序排序
            return d3.ascending(a.value,b.value);//这个地方注意是键值对所以要加上值的引用b.value
        }else{
            //对数据集降序排序
            return d3.descending(a.value,b.value);
        }

    })
    .transition()
    .duration(1000)
    .attr("x",function(d,i){//对排序之后的横坐标重排
        return xScale(i);
    });
};

//创建SVG元素
var svg = d3.select("body")//选中DOM中的目标元素
        .append("svg")//为目标元素附加上一个svg子元素
        .attr("width", w)//设置这个svg的宽
        .attr("height", h);//设置这个svg的高

//为SVG添加条形
svg.selectAll("rect")//选中空元素,表示即将创建这样的元素
    .data(dataset,key)//对此后的方法都执行dataset.length遍
    .enter()//数据元素值比前面选中的DOM元素多就创建一个新的DOM元素
    .append("rect")//取得enter的占位元素,并把rect追加到对应的DOM中
    .attr("x", function(d, i) {//设置横坐标,从0开始每次右移元素宽那么长(w / dataset.length)
            //return i * (w / dataset.length);
            return xScale(i);//这里使用序数比例尺,自己去找刚才划分好的档位
    })
    .attr("y", function(d) {//设置纵坐标,纵坐标正方向是从上往下的,所以条有多长就要设置起点是相对于h再向上移动条长
            return h - yScale(d.value);
    })
    //.attr("width", w / dataset.length - barPadding)//设置元素宽,留出间隙宽barPadding。
    .attr("width", xScale.rangeBand())//这里xScale比例尺已经设置间距了所以直接用
    .attr("height", function(d) {
            return yScale(d.value);
    })
    .attr("fill", function(d) {//设置RGB颜色与数值的关系
            return "rgb(0, 0, " + (d.value * 10) + ")";
    })
    //点击排序
    .on("click",function(){
        sortBars();
    })
    //(3)更新提示条的值和位置
    .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")
        .style("left",xPosition+"px")
        .style("top",yPosition+"px")
        .select("#value")
        .text(d.value);
    })
    //移除提示条 
    .on("mouseout",function(){
        //(4)添加隐藏类
        d3.select("#tooltip").classed("hidden",true);//ID 选择的语法:"#tooltip"
    })
    ;

//为条加上数值
svg.selectAll("text")
   .data(dataset,key)
   .enter()
   .append("text")
   .text(function(d) {
        return d.value;
   })
   .attr("text-anchor", "middle")
   .attr("x", function(d, i) {
        return xScale(i)+xScale.rangeBand()/2;
   })
   .attr("y", function(d) {
        return h - yScale(d.value) + 14;
   })
   .attr("font-family", "sans-serif")
   .attr("font-size",function(d) {
         return xScale.rangeBand()/2;
   })
   .attr("fill", "white");

//删除一条、添加一条
d3.select("p")
.on("click",function(){
    //根据ID确定点击的是哪个标签
    var paragraphID=d3.select(this).attr("id") ; 
    console.log(paragraphID);
    //添加删除组合起来
    if(paragraphID=="add"){
        //数据集最后添加数值
    var maxValue=75;
    var newNumber =Math.floor(Math.random()*maxValue);//0-24的整数
    //根据最后一个key添加一个值
    var lastKeyValue=dataset[dataset.length-1].key; 
        dataset.push({
            key:lastKeyValue+1,
            value:newNumber
        });
    //更新X轴比例尺
    xScale.domain(d3.range(dataset.length));
    //选择所有条
    var bars=svg.selectAll("rect")
    .data(dataset,key); //绑定数据到元素集,返回更新的元素集

    var texts=svg.selectAll("text")
    .data(dataset,key);
    //添加条形元素到最右边
    bars.enter()
    .append("rect")
    .attr("x",w);//在SVG最右边,不可见
    //
    texts.enter()
    .append("text");

    //更新新矩形到可见范围内
    //并在这个时候根据数据集为每个条设置对应的属性
    bars.transition()
        .duration(500)
        .attr("x", function(d, i) {
             return xScale(i) ;
         })//每个X对应到它相应的档位上
        .attr("y", function(d) {
             return h - yScale(d.value) ;
         }) 
        .attr("width", xScale.rangeBand())//这里xScale比例尺已经设置间距了所以直接用
        .attr("height", function(d) {
            return yScale(d.value);
        })
        .attr("fill", function(d) {//设置RGB颜色与数值的关系
            return "rgb(0, 0, " + (d.value * 10) + ")";
        });
        //
    texts.transition()
    .duration(500)
    .text(function(d) {
        return d.value;
    })
    .attr("text-anchor", "middle")
    .attr("x", function(d, i) {
        return xScale(i)+xScale.rangeBand()/2;
    })
    .attr("y", function(d) {
        return h - yScale(d.value) + 14;
    })
    .attr("font-family", "sans-serif")
    .attr("font-size", "12px")
    .attr("fill", "red");

} else if(paragraphID=="remove"){

    //删除的操作
    //选择所有条
    dataset.shift();
    //更新X轴比例尺
    xScale.domain(d3.range(dataset.length));

    var bars=svg.selectAll("rect")
    .data(dataset,key); 
    //从左侧退出
    bars.exit()
    .transition()
    .duration(500)
    .attr("x", -xScale.rangeBand())//w-xScale.rangeBand()间隙宽其实其他负数也行
    .remove();
    }

    });
    // 更新条形数长短的代码,需要一个button标签配合
    //特别注意:这里选中的元素必须在d3选择器之前,或许要先加载完了元素才能被选中
    d3.select("button")
        .on("click",function(){
        // 新数据集,随机数组
        var numValues=dataset.length;
        dataset=[];
        var maxValue=75;
        var newNumber;
        for(var i=0;i<numValues;i++){
            newNumber=Math.floor(Math.random()*maxValue);//0-24的整数
            //根据i添加一个值
            dataset.push({
                key:i,
                value:newNumber
            });
        }

        // 更新比例尺,免使纵坐标超出范围
        yScale.domain([0,d3.max(dataset,value)]);//只要更新定义域就行了,映射到的值域不变
            //更新所有的矩形
            svg.selectAll("rect")
            .data(dataset,key)
            .transition()// 加上过渡动画 
            .delay(function(d,i){
                return  i/dataset.length*1000;
            })//指定过度什么时间开始,可以用函数控制每一条的动画时间,这样就可得到钢琴版的效果
            .duration(2000)// 加上动画的持续时间,以毫秒计算
            .ease("linear")// 缓动函数:有circle(加速)elastic(伸缩),linear(匀速),bounce(弹跳)
            .attr("y",function(d){
                return h-yScale(d.value);
            })
            .attr("height",function(d){
                return yScale(d.value);
            });
            // 更新条上的数值
            svg.selectAll("text")
               .data(dataset,key)
               .text(function(d) {
                    return d.value;
               })
               .attr("text-anchor", "middle")
               .attr("x", function(d, i) {
                    return xScale(i)+xScale.rangeBand()/2;
               })
               .attr("y", function(d) {
                    return h - yScale(d.value) + 14;
               })
               .attr("font-family", "sans-serif")
               .attr("font-size", "12px")
               .attr("fill", "red");
        }); 

        </script>
    </body>
</html>

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值