使用分类(“active”,true)的mouseover上的D3颜色变化

时间:2022-11-20 22:42:53

I'm new to js and D3. I've generated a heatmap of-sorts and would like to change the color of a tile using D3's on.mouseover. I'm able to change the color explicitly but want to use a CSS active rule. Probably something simple to fix. Any help would be greatly appreciated. The full code is below.

我是js和D3的新手。我已经生成了一种热图,并且想要用D3的。mouseover来改变瓷砖的颜色。我可以显式地更改颜色,但希望使用CSS活动规则。可能是一些简单的解决方法。非常感谢您的帮助。完整的代码如下。

Thanks.

谢谢。

<!DOCTYPE html>
<meta charset="utf-8">
<head>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<title>MJ-Heatmap</title>
<header>
<H1>Country By District_Port_Nme Heatmap</H1>
<p></p>
</header>   
<style>
body {
font: 10px sans-serif;
}
.label {
font-weight: bold;
}
.tile {
shape-rendering: crispEdges;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
<!-- CSS active state not working -- >
.tile active {
fill: red;
}
</style>
</head>
<body>
<script type="text/javascript">
var buckets = [
{country:"Brazil", distrinct_port_nme:"Baltimore, Maryland", sum_teu: 2, sum_weight: 18585, count_shipments: 1}, 
{country:"Colombia", distrinct_port_nme:"Baltimore, Maryland", sum_teu:28, sum_weight:258028, count_shipments:11}, 
{country:"Brazil", distrinct_port_nme:"Chicago, Illinois", sum_teu: 2, sum_weight: 18585, count_shipments: 1}, 
{country:"Colombia", distrinct_port_nme:"Houston, Texas", sum_teu:14, sum_weight: 95995, count_shipments: 7}, 
{country:"Brazil", distrinct_port_nme:"Long Beach, California", sum_teu: 2, sum_weight: 18584, count_shipments: 1}, 
{country:"China", distrinct_port_nme:"Long Beach, California", sum_teu: 2, sum_weight: 19180, count_shipments: 1}, 
{country:"Colombia", distrinct_port_nme:"Long Beach, California", sum_teu:12, sum_weight:117873, count_shipments: 6}, 
{country:"Singapore", distrinct_port_nme:"Long Beach, California", sum_teu: 6, sum_weight: 77176, count_shipments: 4}, 
{country:"Belgium", distrinct_port_nme:"Los Angeles, California", sum_teu: 2, sum_weight: 17780, count_shipments: 1}, 
{country:"Brazil", distrinct_port_nme:"Los Angeles, California", sum_teu: 2, sum_weight: 18584, count_shipments: 1}, 
{country:"Colombia", distrinct_port_nme:"Los Angeles, California", sum_teu: 7, sum_weight: 52046, count_shipments: 5}, 
{country:"*", distrinct_port_nme:"Los Angeles, California", sum_teu: 2, sum_weight: 19180, count_shipments: 1}, 
{country:"India", distrinct_port_nme:"Los Angeles, California", sum_teu:48, sum_weight:460563, count_shipments:24}, 
{country:"Singapore", distrinct_port_nme:"Los Angeles, California", sum_teu:12, sum_weight:115384, count_shipments: 6}, 
{country:"Brazil", distrinct_port_nme:"New York, New York", sum_teu: 4, sum_weight: 27032, count_shipments: 2}, 
{country:"Colombia", distrinct_port_nme:"New York, New York", sum_teu: 8, sum_weight: 42885, count_shipments: 4}, 
{country:"India", distrinct_port_nme:"New York, New York", sum_teu:14, sum_weight:129116, count_shipments: 7}, 
{country:"Singapore", distrinct_port_nme:"New York, New York", sum_teu:42, sum_weight:560628, count_shipments:27}, 
{country:"Brazil", distrinct_port_nme:"Newark, New Jersey", sum_teu: 2, sum_weight: 18584, count_shipments: 1}, 
{country:"Colombia", distrinct_port_nme:"Newark, New Jersey", sum_teu:83, sum_weight:785372, count_shipments:42}, 
{country:"India", distrinct_port_nme:"Newark, New Jersey", sum_teu:62, sum_weight:587654, count_shipments:31}, 
{country:"Brazil", distrinct_port_nme:"Norfolk, Virginia", sum_teu: 8, sum_weight: 33622, count_shipments: 4}, 
{country:"India", distrinct_port_nme:"Norfolk, Virginia", sum_teu: 2, sum_weight: 17780, count_shipments: 1}, 
{country:"Brazil", distrinct_port_nme:"Philadelphia, Pennsylvania", sum_teu: 2, sum_weight: 20160, count_shipments: 1}
];
// margins
var margin = {top: 20, right: 90, bottom: 30, left: 100, left_padding: 100},
width = 700 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// axes and color scale
var x = d3.scale.ordinal()
.rangeBands([0, width], .2),
y = d3.scale.ordinal()
.rangeBands([height,0], .2),
z = d3.scale.linear().range(["lightgrey", "steelblue"]);
var xStep = .5,
yStep = 50;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + 0 + "," + margin.top + ")");
// Compute the scale domains.
x.domain(buckets.map(function(d){return d.country}));
y.domain(buckets.map(function(d){return d.distrinct_port_nme}));
z.domain([0, d3.max(buckets.map(function(d){return d.count_shipments}))]);
// Display the tiles for each bucket.
svg.selectAll(".tile")
.data(buckets)
.enter().append("rect")
.attr("class", "tile")
.attr("x", function(d) { return x(d.country) + margin.left+margin.left_padding; })
.attr("y", function(d) { return y(d.distrinct_port_nme); })
.attr("width",x.rangeBand())
.attr("height",y.rangeBand())
.style("stroke","goldenrod")
.style("fill", function(d) { return z(d.count_shipments); })
.on("mouseover", function() { d3.select(this).classed("active", true ) })       // classed("active",boolean) not working
.on("mouseout",  function() { d3.select(this).classed("active", false) });
//  .on("mouseover", function() { d3.select(this).style("fill", "aliceblue");});    // this change work fine
//  .on("mouseout", function(){d3.select(this).style("fill", "white");});           // this change work fine
svg.selectAll("text")
.data(buckets)
.enter().append("text")
.text("text")
.attr("x", function(d) { return x(d.country) + margin.left + margin.left_padding + x.rangeBand()/2; })
.attr("y", function(d) { return y(d.distrinct_port_nme) + y.rangeBand()/2; })
.attr("dx",0)
.attr("dy",".35em")
.attr("text-anchor","middle")
.style("fill","black").attr("font-size","14").attr("font-weight","Bold")
.text( function(d) { return d.count_shipments; });
// Add a legend for the color values.
var legend = svg.selectAll(".legend")
.data(z.ticks(6).slice(1).reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(" + 0 + "," + (10 + i * 20) + ")"; });
legend.append("rect")
.attr("width", 20)
.attr("height", 20)
.style("fill", z);
legend.append("text")
.attr("x", 26)
.attr("y", 10)
.attr("dy", ".35em")
.text(String);
svg.append("text")
.attr("class", "label")
.attr("x", 0)
.attr("y", 0)
.attr("dy", ".35em")
.text("count_shipments");
// Add an x-axis with label.
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate("+ (margin.left+margin.left_padding) + "," + height + ")")
.attr("text_anchor", "top")
.call(d3.svg.axis().scale(x).orient("bottom"))
.append("text")
.attr("class", "label")
.attr("x", width-10)
.attr("y", -5)
.attr("text-anchor", "end")
.text("Country");
// Add a y-axis with label.
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate("+ (margin.left+margin.left_padding) + "," + 0 + ")")
.attr("text-anchor","right")
.call(d3.svg.axis().scale(y).orient("left"))
.append("text")
.attr("class", "label")
.attr("y", 3)
.attr("dy", ".71em")
.attr("text-anchor", "end")
.attr("transform", "rotate(-90)")
.text("distrinct_port_nme");
</script>
</body>
</html>  

1 个解决方案

#1


13  

EDIT

编辑

First off, you were right that your CSS is slightly off.

首先,你是对的,你的CSS有点偏离。

.tile active {
  fill: red;
}

should be:

应该是:

.tile.active {
  fill: red;
}

Then, sort of like I explained below, the fill you're applying to the element with

然后,就像我在下面解释的一样,你要用的填充元素。

.style("fill", function(d) { return z(d.count_shipments); })

ends up taking precedence over the fill applied by the active class.

最终优先于由活动类应用的填充。

However, unlike what I initially suggested, you can work around it by simply swapping style with attr, so you need:

但是,与我最初建议的不同,您可以通过简单的与attr交换样式来解决它,所以您需要:

.attr("fill", function(d) { return z(d.count_shipments); })

(probably should do this for stroke as well).

(可能也应该这样做)。

Here's an updated, working jsFiddle

这里有一个更新的,工作的jsFiddle。


ORIGINAL POST

最初的发布

I suspect it works the way it should –– i.e. class "active" with its associated fill is being added/removed appropriately –– and you'd be able to verify this by right-clicking and inspecting the element in dev tools.

我怀疑它是按照它应该的方式工作的——也就是说,它的关联填充的类“active”正在被适当地添加/删除——并且您可以通过右键单击并检查dev工具中的元素来验证这一点。

I think the real problem is that you're also setting a fill directly on the element (one line before your .on("mouseover"...) call), which ALWAYS overrides the fill applied by your class. Generally in CSS you could (not saying you should) use the !important keyword to force it to accept the fill applied by the class. But I'm pretty sure that won't work with SVG (as opposed to normal HTML elements).

我认为真正的问题是,您还将直接在元素上设置一个填充(在您的.on(“mouseover”…)调用之前的一行),它总是覆盖您的类所应用的填充。通常在CSS中,你可以(不是说你应该)使用!重要的关键字来强迫它接受类的填充。但是我很确定这不会与SVG(与普通的HTML元素相反)工作。

So, I think your only option is:

所以,我认为你唯一的选择是:

.style("fill", function(d) { return z(d.count_shipments); })
.on("mouseover", function() {
  d3.select(this)
    .attr('fill', '') // Un-sets the "explicit" fill (might need to be null instead of '')
    .classed("active", true ) // should then accept fill from CSS
})
.on("mouseout",  function() {
  d3.select(this)
    .classed("active", false)
    .attr('fill', function(d) { return z(d.count_shipments); }) // Re-sets the "explicit" fill
  });

Hope this works....

希望这作品....

#1


13  

EDIT

编辑

First off, you were right that your CSS is slightly off.

首先,你是对的,你的CSS有点偏离。

.tile active {
  fill: red;
}

should be:

应该是:

.tile.active {
  fill: red;
}

Then, sort of like I explained below, the fill you're applying to the element with

然后,就像我在下面解释的一样,你要用的填充元素。

.style("fill", function(d) { return z(d.count_shipments); })

ends up taking precedence over the fill applied by the active class.

最终优先于由活动类应用的填充。

However, unlike what I initially suggested, you can work around it by simply swapping style with attr, so you need:

但是,与我最初建议的不同,您可以通过简单的与attr交换样式来解决它,所以您需要:

.attr("fill", function(d) { return z(d.count_shipments); })

(probably should do this for stroke as well).

(可能也应该这样做)。

Here's an updated, working jsFiddle

这里有一个更新的,工作的jsFiddle。


ORIGINAL POST

最初的发布

I suspect it works the way it should –– i.e. class "active" with its associated fill is being added/removed appropriately –– and you'd be able to verify this by right-clicking and inspecting the element in dev tools.

我怀疑它是按照它应该的方式工作的——也就是说,它的关联填充的类“active”正在被适当地添加/删除——并且您可以通过右键单击并检查dev工具中的元素来验证这一点。

I think the real problem is that you're also setting a fill directly on the element (one line before your .on("mouseover"...) call), which ALWAYS overrides the fill applied by your class. Generally in CSS you could (not saying you should) use the !important keyword to force it to accept the fill applied by the class. But I'm pretty sure that won't work with SVG (as opposed to normal HTML elements).

我认为真正的问题是,您还将直接在元素上设置一个填充(在您的.on(“mouseover”…)调用之前的一行),它总是覆盖您的类所应用的填充。通常在CSS中,你可以(不是说你应该)使用!重要的关键字来强迫它接受类的填充。但是我很确定这不会与SVG(与普通的HTML元素相反)工作。

So, I think your only option is:

所以,我认为你唯一的选择是:

.style("fill", function(d) { return z(d.count_shipments); })
.on("mouseover", function() {
  d3.select(this)
    .attr('fill', '') // Un-sets the "explicit" fill (might need to be null instead of '')
    .classed("active", true ) // should then accept fill from CSS
})
.on("mouseout",  function() {
  d3.select(this)
    .classed("active", false)
    .attr('fill', function(d) { return z(d.count_shipments); }) // Re-sets the "explicit" fill
  });

Hope this works....

希望这作品....