【问题标题】:How do I add a transform attribute to svg subgroups in d3.js?如何在 d3.js 中向 svg 子组添加转换属性?
【发布时间】:2017-08-05 05:26:24
【问题描述】:

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

我想在鼠标悬停时为每个具有“单元格”类的图块(一个 svg 矩形)设置动画。我已经尝试将其放入页面的样式部分:

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

【问题讨论】:

    标签: d3.js svg


    【解决方案1】:

    您可以简单地为每个单独的矩形分配一个事件侦听器,然后您可以根据您想要的持续时间、绑定到它的数据等很好地为其设置动画。

    为此,您将跳过 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);
    }
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.min.js"&gt;&lt;/script&gt;

    【讨论】:

    • 非常好,让我可以做更多的事情。现在这是一个相关的曲线球:有没有办法实现“悬停在附近”功能,其中对象 near 鼠标指针(通过某个定义的距离),但不完全在它下面,做些什么?出于我自己的兴趣,只是一个随意的问题(不值得完整输入)。
    • 最近有个问题,希望对这个问答有所帮助:stackoverflow.com/questions/42743543/…
    • 安德鲁只是一个小问题。在您的版本中,旋转工作正常,但在我的热图示例中,添加您的(.on mouseover 和 mouseout,以及相同的旋转和取消旋转功能),瓷砖相对于整个热图的原点旋转,而不是与尊重瓷砖本身。
    • 如果我理解:旋转将相对于元素相对于其父元素的 x,y 值。因此,在我的示例中,我附加了一个带有变换的父 g 元素,并在父元素 g 中附加了每个矩形,这样矩形中心在父元素中为零。希望这是有道理的。
    • @ThomasBrowne 这个“旋转”问题很常见。像 Andrew 一样,使用 transform 属性来定位矩形。省去了计算坐标系原点的麻烦,看看我的回答:stackoverflow.com/a/42643557/5768908
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-16
    • 2021-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多