如何在d3.js中为svg子组添加转换属性?

时间:2017-03-14 18:04:55

标签: d3.js svg

Here是d3.js中非常漂亮,简单的热图示例。

我想在鼠标悬停时为每个图块(一个svg rect)设置动画,该图块有一个" cell"类。我已经尝试将其放入页面的样式部分:

svg:hover .cell {
  transform: rotate(45 deg);
}

但这会旋转整个热图。如何设置svg变换以对每个单独的磁贴进行操作?您会注意到每个磁贴都在其自己的g(组)标记中,但整个svg也在一个组中。是否可以使用d3.js将变换属性设置为单个(嵌套)svg元素?

供参考,以下是完整代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  .axis path,
  .axis line {
    fill: none;
    stroke: black;
    shape-rendering: crispEdges;
  }

  .axis text {
      font-family: sans-serif;
      font-size: 11px;
  }

  svg:hover .cell {
    transform: rotate(45deg);
  }

</style>

<div class="heatmap"></div>

<script src="//d3js.org/d3.v3.min.js"></script>

<script>
  var itemSize = 22,
      cellSize = itemSize - 1,
      margin = {top: 120, right: 20, bottom: 20, left: 110};

  var width = 750 - margin.right - margin.left,
      height = 300 - margin.top - margin.bottom;

  var formatDate = d3.time.format("%Y-%m-%d");

  d3.csv('data.csv', function ( response ) {

    var data = response.map(function( item ) {
        var newItem = {};
        newItem.country = item.x;
        newItem.product = item.y;
        newItem.value = item.value;

        return newItem;
    })

    var x_elements = d3.set(data.map(function( item ) { return item.product; } )).values(),
        y_elements = d3.set(data.map(function( item ) { return item.country; } )).values();

    var xScale = d3.scale.ordinal()
        .domain(x_elements)
        .rangeBands([0, x_elements.length * itemSize]);

    var xAxis = d3.svg.axis()
        .scale(xScale)
        .tickFormat(function (d) {
            return d;
        })
        .orient("top");

    var yScale = d3.scale.ordinal()
        .domain(y_elements)
        .rangeBands([0, y_elements.length * itemSize]);

    var yAxis = d3.svg.axis()
        .scale(yScale)
        .tickFormat(function (d) {
            return d;
        })
        .orient("left");

    var colorScale = d3.scale.threshold()
        .domain([0.85, 1])
        .range(["#2980B9", "#E67E22", "#27AE60", "#27AE60"]);

    var svg = d3.select('.heatmap')
        .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var cells = svg.selectAll('rect')
        .data(data)
        .enter().append('g').append('rect')
        .attr('class', 'cell')
        .attr('width', cellSize)
        .attr('height', cellSize)
        .attr('y', function(d) { return yScale(d.country); })
        .attr('x', function(d) { return xScale(d.product); })
        .attr('fill', function(d) { return colorScale(d.value); });

    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis)
        .selectAll('text')
        .attr('font-weight', 'normal');

    svg.append("g")
        .attr("class", "x axis")
        .call(xAxis)
        .selectAll('text')
        .attr('font-weight', 'normal')
        .style("text-anchor", "start")
        .attr("dx", ".8em")
        .attr("dy", ".5em")
        .attr("transform", function (d) {
            return "rotate(-65)";
        });
  });
</script>

这是data.csv文件,它必须与html位于同一目录中。

x,y,value
France,Apricot,2.3129545439964723
France,Avocado,3.1610140317890965
France,Lemon,0.9075695440623942
France,Date,1.1296454803177811
France,Strawberry,
France,Mandarin,2.6193568568512493
France,Chestnut,0.08748279136251946
France,Nuts,2.943858242639327
France,Olive,1.3356914547843943
France,Mirabelle,0.31390905400247027
France,Orange,0.5709024568447734
France,Fig,0.8689875977541086
France,Raisin,
France,Pear,
France,Potato,
France,Khaki,
France,Kiwi,6.026783469350332
France,Pumpkin,0.5472217416389179
France,Mango,
France,Cherry,1.9472375734686518
Italy,Apricot,2.250335336990016
Italy,Avocado,1.4472931892677967
Italy,Lemon,1.7163168911863054
Italy,Date,0.6222770814456479
Italy,Strawberry,
Italy,Mandarin,1.9378611429750559
Italy,Goyave,
Italy,Chestnut,0.35446193006796944
Italy,Nuts,0.37199215156032084
Italy,Olive,1.05979039016384
Italy,Orange,1.9087621718437413
Italy,Fig,4.632439392448328
Italy,Raisin,
Italy,Pear,
Italy,Potato,
Italy,Khaki,
Italy,Banana,
Italy,Blackcurrant,
Italy,Kiwi,1.673923311217576
Italy,Pumpkin,0.8029920360319587
Italy,Cherry,1.9453249240219272
Germany,Apricot,0.24786564820472912
Germany,Avocado,1.13545847239482
Germany,Lemon,0.6388067539810734
Germany,Date,1.626323182055196
Germany,Strawberry,
Germany,Mandarin,0.4239980281990543
Germany,Chestnut,1.4341389749588975
Germany,Nuts,0.7392983316104583
Germany,Olive,1.6630071601899028
Germany,Mirabelle,4.759329801939115
Germany,Orange,3.718673834416696
Germany,Fig,2.458679694479642
Germany,Raisin,
Germany,Pear,
Germany,Potato,
Germany,Prune,
Germany,Khaki,
Germany,Banana,
Germany,Ananas,
Germany,Kiwi,1.3234705953824204
Germany,Pumpkin,0.0770059996293927
Germany,Cherry,1.7111604775075815
United Kingdom,Apricot,0.17924671480874477
United Kingdom,Avocado,0.022885648078082133
United Kingdom,Lemon,1.7152082470441878
United Kingdom,Date,1.752070575653172
United Kingdom,Mandarin,3.4281163770331387
United Kingdom,Goyave,
United Kingdom,Chestnut,0.19739811992921974
United Kingdom,Nuts,1.0070422960846344
United Kingdom,Olive,2.228287010523628
United Kingdom,Orange,0.9304979227921532
United Kingdom,Fig,0.5953329645659061
United Kingdom,Cerise,
United Kingdom,Raisin,
United Kingdom,Potato,
United Kingdom,Prune,
United Kingdom,Khaki,
United Kingdom,Ananas,
United Kingdom,Kiwi,3.9494022464067755
United Kingdom,Pumpkin,2.2009939178127476
United Kingdom,Mango,
United Kingdom,Cherry,0.20063602688693316
Spain,Apricot,0.9989751140631283
Spain,Avocado,1.3798561037495776
Spain,Lemon,4.621063369745371
Spain,Date,2.715496746864414
Spain,Strawberry,
Spain,Mandarin,4.655686656785712
Spain,Chestnut,2.0830024325290624
Spain,Nuts,3.8907348191368603
Spain,Olive,0.4593907900702838
Spain,Mirabelle,0.8657861030686699
Spain,Orange,3.431725506748977
Spain,Fig,6.387945884767135
Spain,Raisin,
Spain,Pear,
Spain,Potato,
Spain,Khaki,
Spain,Kiwi,1.1520183768223036
Spain,Pumpkin,1.9614971869756583
Spain,Cherry,1.7489279548209826

1 个答案:

答案 0 :(得分:3)

您可以简单地为每个单独的矩形指定一个事件监听器,然后您可以根据所需的持续时间,绑定到它的数据等对其进行很好的动画处理。

为此,您可以跳过css样式,只需在追加每个单元格时为其创建mouseovermouseout个事件:

var svg = d3.select('body')
  .append('svg')
  .attr('width',500)
  .attr('height',200);
  
var g = svg.selectAll('g')
  .data(d3.range(40))
  .enter()
  .append('g')
  .attr("transform",function(d,i) { return      "translate("+(i%10*40+40)+","+(Math.floor(i/10)* 40+40)+")";});

g.append('rect')
  .attr('width',30)
  .attr('height',30)
  .attr('x',-15)
  .attr('y',-15)
  .on('mouseover',rotate)
  .on('mouseout',unrotate);
  
function rotate() {
  d3.select(this)
    .transition()
    .attr('fill','orange')
    .attr('transform','rotate(45)')
    .duration(200);
}

function unrotate() {
  d3.select(this)
   .transition()
   .attr('fill','black')
   .attr('transform','rotate(0)')
   .duration(200);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.min.js"></script>