d3 mouseover事件不适用于所有rect

时间:2017-01-24 21:15:28

标签: javascript d3.js mouseover

我有一个带有鼠标悬停事件的简单条形图。在数据更新之前,代码仅在函数 changeData 之外。但是在数据发生变化之后,只在函数内部工作代码。 如何为所有rectangels编写处理mouseover / out的函数?

使用按钮 OpacityNow 我可以将不透明度更改为所有rects,无论数据是否已更改。

感谢您的帮助。

  var myCanvas1 = d3.select("#chart1")
   .append("svg")
   .attr("width", svgWidth + margin.left + margin.right)
   .attr("height", svgHeight + margin.top + margin.bottom)
   .style("background", "aliceblue")
   .append("g")
   .attr("transform","translate(" + margin.left + "," + margin.top + ")")
   .append("g");

   //append rectangles to svg container
  var Bar = myCanvas1.selectAll("rect")
    .data(dataArray1)
    .enter()
    .append("rect")
    .style("fill", "steelblue")
    .attr("x", function(d, i) { return x(i); })
    .attr("width", x.bandwidth())
    .attr("y", function(d) { return (svgHeight - y(+d.balance)); } )
    .attr("height", function(d) { return y(+d.balance); })
    //.on("mouseover", function() {d3.select(this).attr("opacity", 0.5)})
    //.on("mouseout", function() {d3.select(this).attr("opacity", 1)});

  //function for button click event
   function changeData(myDataArray) {

    var Bars = myCanvas1.selectAll("rect");
    var NewBars = Bars.data(eval(myDataArray));
    //enter new data
    NewBars.enter()
        .append("rect")
        .style("fill", "steelblue")
        //.on("mouseover", function() {d3.select(this).attr("opacity", 0.5)})
        //.on("mouseout", function() {d3.select(this).attr("opacity", 1)})
        .transition()
        .duration(duration1)
        .attr("x", function(d, i) { return x(i); })
        .attr("width", x.bandwidth())
        .attr("y", function(d) { return (svgHeight - y(+d.balance)); } )
        .attr("height", function(d) { return y(+d.balance); });
    //exit data
    NewBars.exit()
        .remove();
    //update data
    NewBars.transition()
        .duration(duration1)
        .style("fill", "steelblue")
        .attr("x", function(d, i) { return x(i); })
        .attr("width", x.bandwidth())
        .attr("y", function(d) { return (svgHeight - y(+d.balance)); } )
        .attr("height", function(d) { return y(+d.balance); });

    //mouseover and mouseout event functions
    d3.select("#chart1").select("svg").selectAll("rect").on("mouseover", function(d) { d3.select(this).attr("opacity", 0.3)});
    d3.select("#chart1").select("svg").selectAll("rect").on("mouseout", function(d) { d3.select(this).attr("opacity", 1)});
   };

    //mouseover and mouseout event functions
  d3.select("#chart1").select("svg").selectAll("rect").on("mouseover", function(d) { d3.select(this).style("fill", "red")});
  d3.select("#chart1").select("svg").selectAll("rect").on("mouseout", function(d) { d3.select(this).style("fill", "green")});

    //function click button to change opacity in all rects
   function OpacityNow() {
      d3.select("#chart1").select("svg").selectAll("rect").style("opacity", 0.3);
   };
   //function click button to change color in all rects
   function ColorNow() {
       d3.select("#chart1").select("svg").selectAll("rect").style("fill", "green");
   };

1 个答案:

答案 0 :(得分:0)

这是预期的行为。与按之后运行的按钮代码不同,单击按钮时,鼠标悬停代码会将事件处理程序绑定到当时SVG 中存在的<rect>元素

以下是一些演示它的代码。

假设我们有这种模式:

//code for creating the bars
.on("mouseover", function(){ ... }//mouseover block, outside 'update'

update();

function update(){
    //code for updating the bars
}

在这种情况下,mouseover将在运行更新函数之前处理创建的条形图。

这是一个向您展示的演示。您可以看到鼠标悬停首先适用于所有rects,但是,当创建新的矩形时,它不再起作用:

var width = 400, height = 400;

var margin = {top:0, right:0, bottom:0, left:30};

var svg = d3.select("body")
	.append("svg")
	.attr("width", width)
	.attr("height", height);
	
var xScale = d3.scaleLinear()
	.range([margin.left, width - margin.right]);
	
var yScale = d3.scaleBand()
	.range([margin.top, height - margin.bottom])
	.paddingInner(0.2);
	
var yAxis = d3.axisLeft(yScale)
	.tickSizeOuter(0);
	
var letters = "ABCDEFGHIJ".split("");
	
var color = d3.scaleSequential(d3.interpolateViridis)
	.domain([0, 10]);
	
svg.append("g")
	.attr("class", "y axis")
	.attr("transform", "translate(" + margin.left + ",0)")
	.call(yAxis);
	
draw();
	
function draw(){

var data = getData();
	
xScale.domain([0, d3.max(data, function(d){ return d.value})]);
yScale.domain(data.map(function(d){ return d.title}));

var bars = svg.selectAll(".bars")
	.data(data, function(d){ return d.title});
	
bars.exit()
	.transition()
	.duration(1000)
	.attr("width", 0)
	.remove();
	
bars.enter()
	.append("rect")
	.attr("class", "bars")
	.attr("x", xScale(0) + 1)
	.attr("y", function(d){ return yScale(d.title)})
	.attr("width", 0)
	.attr("height", yScale.bandwidth())
	.attr("fill", function(d){ return color(letters.indexOf(d.title)+1)})
	.merge(bars).transition()
	.duration(1000)
	.delay(1000)
	.attr("y", function(d){ return yScale(d.title)})
	.attr("width", function(d){ return xScale(d.value)});

	d3.transition(svg).select(".y.axis")
			.transition()
			.duration(1000)
			.delay(750)
			.call(yAxis);
}

function getData(){
	var title = "ABCDEFGHIJ".split("");
	var data = [];
	for(var i = 0; i < 5; i++){
		var index = Math.floor(Math.random()*title.length);
		data.push({title: title[index],
		value: Math.floor(Math.random()*100)});
		title.splice(index,1);
	}
	data = data.sort(function(a,b){ return d3.ascending(a.title,b.title)});
	return data;
};

setInterval(draw, 3000);

d3.selectAll("rect").on("mouseover", function(){
    d3.select(this).attr("opacity", .5)
}).on("mouseout", function(){
    d3.select(this).attr("opacity", 1)
});
	
	
<script src="https://d3js.org/d3.v4.min.js"></script>

现在,让我们做另一种模式:

//code for creating the bars

update();

function update(){
    //code for updating the bars
    .on("mouseover", function(){ ... }//mouseover block, inside 'update'
}

在这种情况下,只有调用函数update后,鼠标悬停才能正常工作。这是另一个演示,该函数将在5秒后调用:

var width = 400, height = 400;

var margin = {top:0, right:0, bottom:0, left:30};

var svg = d3.select("body")
	.append("svg")
	.attr("width", width)
	.attr("height", height);
	
var xScale = d3.scaleLinear()
	.range([margin.left, width - margin.right]);
	
var yScale = d3.scaleBand()
	.range([margin.top, height - margin.bottom])
	.paddingInner(0.2);
	
var yAxis = d3.axisLeft(yScale)
	.tickSizeOuter(0);
	
var letters = "ABCDEFGHIJ".split("");
	
var color = d3.scaleSequential(d3.interpolateViridis)
	.domain([0, 10]);
	
svg.append("g")
	.attr("class", "y axis")
	.attr("transform", "translate(" + margin.left + ",0)")
	.call(yAxis);
	
var data = getData();
	
xScale.domain([0, d3.max(data, function(d){ return d.value})]);
yScale.domain(data.map(function(d){ return d.title}));

var bars = svg.selectAll(".bars")
	.data(data, function(d){ return d.title});
	
bars.exit()
	.transition()
	.duration(1000)
	.attr("width", 0)
	.remove();
	
bars.enter()
	.append("rect")
	.attr("class", "bars")
	.attr("x", xScale(0) + 1)
	.attr("y", function(d){ return yScale(d.title)})
	.attr("width", 0)
	.attr("height", yScale.bandwidth())
	.attr("fill", function(d){ return color(letters.indexOf(d.title)+1)})
	.merge(bars).transition()
	.duration(1000)
	.delay(1000)
	.attr("y", function(d){ return yScale(d.title)})
	.attr("width", function(d){ return xScale(d.value)});
	
		d3.transition(svg).select(".y.axis")
			.transition()
			.duration(1000)
			.delay(750)
			.call(yAxis);
	
function draw(){

var data = getData();
	
xScale.domain([0, d3.max(data, function(d){ return d.value})]);
yScale.domain(data.map(function(d){ return d.title}));

var bars = svg.selectAll(".bars")
	.data(data, function(d){ return d.title});
	
bars.exit()
	.transition()
	.duration(1000)
	.attr("width", 0)
	.remove();
	
bars.enter()
	.append("rect")
	.attr("class", "bars")
	.attr("x", xScale(0) + 1)
	.attr("y", function(d){ return yScale(d.title)})
	.attr("width", 0)
	.attr("height", yScale.bandwidth())
	.attr("fill", function(d){ return color(letters.indexOf(d.title)+1)})
	.merge(bars).transition()
	.duration(1000)
	.delay(1000)
	.attr("y", function(d){ return yScale(d.title)})
	.attr("width", function(d){ return xScale(d.value)});
	
	d3.selectAll("rect").on("mouseover", function(){
    d3.select(this).attr("opacity", .5)
}).on("mouseout", function(){
    d3.select(this).attr("opacity", 1)
});

	d3.transition(svg).select(".y.axis")
			.transition()
			.duration(1000)
			.delay(750)
			.call(yAxis);
}

function getData(){
	var title = "ABCDEFGHIJ".split("");
	var data = [];
	for(var i = 0; i < 5; i++){
		var index = Math.floor(Math.random()*title.length);
		data.push({title: title[index],
		value: Math.floor(Math.random()*100)});
		title.splice(index,1);
	}
	data = data.sort(function(a,b){ return d3.ascending(a.title,b.title)});
	return data;
};

setInterval(draw, 5000);
<script src="https://d3js.org/d3.v4.min.js"></script>

只有在那之后,鼠标悬停才会起作用。

正如我之前所说,该按钮适用于在update功能之前或之后创建的所有矩形,因为它会在按下按钮时选择SVG 中显示的矩形

如果您不想重复代码(如果您的mouseovermouseout函数变大),您可以单独设置这些功能:

//code for creating the bars
.on("mouseover", mouseover)//calls 'mouseover'
.on("mouseout", mouseout)//calls 'mouseout'

function update(){
    //code for updating the bars
    .on("mouseover", mouseover)//calls 'mouseover'
    .on("mouseout", mouseout)//calls 'mouseout'
}

function mouseover(){ ... }
function mouseout(){ ... }

以下是演示:

var width = 400, height = 400;

var margin = {top:0, right:0, bottom:0, left:30};

var svg = d3.select("body")
	.append("svg")
	.attr("width", width)
	.attr("height", height);
	
var xScale = d3.scaleLinear()
	.range([margin.left, width - margin.right]);
	
var yScale = d3.scaleBand()
	.range([margin.top, height - margin.bottom])
	.paddingInner(0.2);
	
var yAxis = d3.axisLeft(yScale)
	.tickSizeOuter(0);
	
var letters = "ABCDEFGHIJ".split("");
	
var color = d3.scaleSequential(d3.interpolateViridis)
	.domain([0, 10]);
	
svg.append("g")
	.attr("class", "y axis")
	.attr("transform", "translate(" + margin.left + ",0)")
	.call(yAxis);
	
draw();
	
function draw(){

var data = getData();
	
xScale.domain([0, d3.max(data, function(d){ return d.value})]);
yScale.domain(data.map(function(d){ return d.title}));

var bars = svg.selectAll(".bars")
	.data(data, function(d){ return d.title});
	
bars.exit()
	.transition()
	.duration(1000)
	.attr("width", 0)
	.remove();
	
bars.enter()
	.append("rect")
	.attr("class", "bars")
	.attr("x", xScale(0) + 1)
	.attr("y", function(d){ return yScale(d.title)})
	.attr("width", 0)
	.attr("height", yScale.bandwidth())
	.attr("fill", function(d){ return color(letters.indexOf(d.title)+1)})
	.merge(bars).transition()
	.duration(1000)
	.delay(1000)
	.attr("y", function(d){ return yScale(d.title)})
	.attr("width", function(d){ return xScale(d.value)});
  
  d3.selectAll("rect").on("mouseover", mouseover).on("mouseout", mouseout);

	d3.transition(svg).select(".y.axis")
			.transition()
			.duration(1000)
			.delay(750)
			.call(yAxis);
}

function getData(){
	var title = "ABCDEFGHIJ".split("");
	var data = [];
	for(var i = 0; i < 5; i++){
		var index = Math.floor(Math.random()*title.length);
		data.push({title: title[index],
		value: Math.floor(Math.random()*100)});
		title.splice(index,1);
	}
	data = data.sort(function(a,b){ return d3.ascending(a.title,b.title)});
	return data;
};

setInterval(draw, 3000);

d3.selectAll("rect").on("mouseover", mouseover).on("mouseout", mouseout);

function mouseover(){
  d3.select(this).attr("opacity", .5);
}

function mouseout(){
  d3.select(this).attr("opacity", 1);
}
<script src="https://d3js.org/d3.v4.min.js"></script>