您的位置:首页 > Web前端 > JavaScript

【D3.js数据可视化系列教程】(十七)--通过键联结数据

2013-11-02 19:48 716 查看
最后效果:点击删除会从左侧消失。数值和条是对应的,即添加一条时更新位置后对应条上的数值还在这条上。

1. 键值对数据集

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},
...
];

2. 更新数据引用,包含下面所有关于要使用到d.value的地方

.domain([0,d3.max(dataset,function(d){
return d.value;
})])
.range([0,h]);

3. 定义键函数(简洁),以备数据绑定到元素的时候使用

var key=function(d){
return d.key;
};

4. 从左侧退出

bars.exit().transition().duration(500)
.attr("x", -xScale.rangeBand())//w-xScale.rangeBand()间隙宽其实其他负数也行
.remove();});

5. 实现键联结数据

<!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 :orange;
}
/* 过渡效果*/
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" class="click">单击删除</p><div id="add" class="click">单击添加</div>
<br>

<!-- (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.selectAll("text")
.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)+ xScale.rangeBand() / 2;
});
};

d3.select("#tooltip").classed("hidden", true);

//创建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);
d3.select("#tooltip").classed("hidden", false);
})
//移除提示条
.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.selectAll(".click")
.on("click",function() {
//根据ID确定点击的是哪个标签
var paragraphID = d3.select(this).attr("id");
//添加删除组合起来
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()
.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 {
//删除的操作
//选择所有条
dataset.shift();
//更新X轴比例尺
xScale.domain(d3.range(dataset.length));

var bars = svg.selectAll("rect").data(dataset, key);
var texts = svg.selectAll("text").data(dataset, key);
//从左侧退出
bars.exit().transition().duration(500)
.attr("x", -xScale.rangeBand())//w-xScale.rangeBand()间隙宽其实其他负数也行
.remove();
//从左侧退出
texts.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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息