【发布时间】:2014-12-09 20:40:35
【问题描述】:
我有一个带有一些过滤器控件作为复选框的 SVG 圆圈图。圆圈有一个进入过渡(过滤器被选中 - 进入屏幕)、一个退出过渡(过滤器未被选中 - 离开屏幕)和一个更新过渡(过滤器悬停在 - 突出显示元素)。
由于我使用相同的控件来进入/退出/突出显示(即复选框),因此每当我取消选中过滤器然后将鼠标移开时,突出显示转换会取消退出转换并且圆圈会停留在任何位置它即将退出。
有没有办法链接高亮过渡,这样它就不会取消退出过渡?有没有办法标记转换,以便我可以根据活动转换的标签链接或中断?我不认为我可以使用transition.each 或transition.transition 方法,因为退出转换选择的元素可能与突出显示转换选择的元素不同(例如,用户单击过滤器1 然后将鼠标悬停在过滤器2 上)。
明确地说,最终目标是
- 如果活动转换是进入/退出
- 如果后续转换是进入/退出,则中断并应用
- 如果后续过渡是突出显示的,则链接
- 如果活动过渡被突出显示
- 如果随后的过渡是突出显示,中断并应用
- 如果后续转换是进入/退出,则链式
这可以归结为
- 如果后续转换与活动转换相同,则中断并应用
- 如果后续转换与主动转换不同,则链接
将鼠标悬停在按钮上会突出显示各种圆圈,单击它会删除它们。尝试单击并将鼠标移开以查看问题。
// Setup container
var container = d3.selectAll('#svgContainer');
var width = 640,
height = 480;
var nShapes = 50;
// Create random data
var filteredData,
data = d3.range(nShapes).map(function(d, i) {
return {
id: i,
x: Math.floor(Math.random() * width),
y: Math.floor(Math.random() * height),
r: Math.floor(Math.random() * width / 15),
red: Math.floor(Math.random() * 100),
blue: Math.floor(Math.random() * 100)
};
});
// Create filter functions
var filters = {
red: function(d) {return d.red > 50;},
blue: function(d) {return d.blue > 50;}
};
// Create SVG
var svg = container.append('svg')
.attr({
width: width,
height: height
});
// Hook up hover handlers for filters
$(".filter").hover(function(e) {return onHover(e, this.dataset['filter']);});
// Hook up click handlers for filters
$(".filter").change(function(e) {
filterData();
draw();
});
// Filter data and draw the canvas
filterData();
draw();
/**
* Recalcualte filtered data
*/
function filterData() {
filteredData = data;
$('.filter').each(function(idx, el) {
var filterName = this.dataset['filter'];
var filteredOut = !$(this).find("input").prop('checked');
if (filteredOut) filteredData = filteredData.filter(function(d) {
return !filters[filterName](d);
});
});
}
/**
* Hover handler
*/
function onHover(event, filterName) {
var isHovering = (event.type == "mouseenter");
svg.selectAll('.shape')
.filter(filters[filterName])
.transition().duration(100)
.attr({
r: function (d) {return isHovering ? 1.5 * d.r : d.r;}
})
.style({
opacity: isHovering ? 0.5 : 1.0
});
}
/**
* Draw function
*/
function draw() {
var duration = 750;
var shapes = svg.selectAll('.shape').data(filteredData, function(d) {
return d.id;
});
shapes.enter().append('circle') // apply to enter selection only
.attr('class', 'shape')
.attr({
cx: 0,
cy: 0,
r: 0
})
.style('fill', 'white');
shapes.transition().duration(duration) // apply to enter + update selection
.delay(function(d) {return (d.id / nShapes) * duration;})
.attr({
cx: function(d) {return d.x;},
cy: function(d) {return d.y;},
r: function(d) {return d.r;}
})
.style({
fill: function(d) {
if (filters.red(d) && filters.blue(d)) return "purple";
if (filters.red(d)) return "red";
if (filters.blue(d)) return "blue";
return "green";
}
});
shapes.exit().transition().duration(duration) // apply to exit selection only
.delay(function(d) {return (d.id / nShapes) * duration;})
.attr({
cx: 0,
cy: 0,
r: 0
})
.style('fill', 'white')
.remove();
}
svg {
border: 1px solid black;
}
.shape {
fill-opacity: 0.9;
}
label {
margin-right: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<label id="red" class="filter" data-filter="red">
<input type="checkbox" checked />Red Filter</label>
<label id="blue" class="filter" data-filter="blue">
<input type="checkbox" checked />Blue Filter</label>
<div id="svgContainer"></div>
【问题讨论】:
-
在 D3 中,安排新的过渡总是会取消现有的过渡。但是,您可以检查元素上是否已经存在转换(检查数据中的
.__transition__属性),如果是这种情况,则不要安排新的转换。 -
@LarsKotthoff 我之前实际上已经尝试过,但没有成功。在某些情况下,
mouseleave上的突出显示转换不会中断mouseenter上的突出显示转换,并且圆圈将保持突出显示。这是因为我无法检查 哪个 转换处于活动状态(即,如果前一个正在突出显示,但如果它正在进入/退出,我想中断转换)。 -
嗯,在给定的时间只能有一个过渡活动,所以我不完全确定你在说什么。你的意思是你有几个过渡同时工作?
-
@LarsKotthoff 我对问题进行了编辑,以更明确地说明最终目标(我还更新了 sn-p 以包含输入转换和更好的过滤器可视化)。
-
啊,我明白你的意思了。我会存储一个属性,其中包含表示当前转换类型的数据,您可以检查一下是否应该稍后取消它。
标签: javascript svg d3.js transition