d3js:在气泡和文本上一起应用动画

时间:2017-10-16 09:55:04

标签: javascript css d3.js svg

我有一个包含圆圈和一些文字的气泡车。在检查图表时,我得到这样的结果:

inspect

问题是我应用的动画仅适用于圆圈。我想以某种方式将圆圈和文本组合在一起,然后在每个组上应用动画。 就像我指定的那样,有2个事件:mouseover和mouseout。我想将它们应用于圆圈和圆圈内的文本。

我的脚本如下:

var margin = 40,
width = 600,
height = 400;

var data = [{"admit_probability":54,"rank":20, "c":12},
            {"admit_probability":79,"rank":111, "c":9},
            {"admit_probability":70,"rank":68, "c":6},
            {"admit_probability":12,"rank":1, "c":20},
            {"admit_probability":197,"rank":87, "c":10}];

var xscale = d3.scaleLinear()
              .domain(
                    d3.extent(data, function(d) { return +d.admit_probability; })
                )
              .nice() 
              .range([0, width]);

var yscale = d3.scaleLinear()
              .domain(d3.extent(data, function(d) { return +d.rank; }))
              .nice()
              .range([height, 0]);

var xAxis = d3.axisBottom().scale(xscale);

var yAxis = d3.axisLeft().scale(yscale);

var svg = d3.select('.chart')
                .append('svg')
                .attr('class', 'chart')
                .attr("width", width + margin + margin)
                .attr("height", height + margin + margin)
                .append("g")
                .attr("transform", "translate(" + margin + "," + margin + ")");

svg.append("g")
    .attr("class", "y axis")
    .call(yAxis);

svg.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis);

var color = d3.scaleOrdinal(d3.schemeCategory10);

svg.selectAll("circle")
   .data(data)
   .enter()
   .insert("circle")
   .attr("cx", width / 2)
   .attr("cy", height / 2)
   .attr("opacity", 0.3)
   .attr("r", 20)
   .style("fill", "blue")
   .on('mouseover', function (d, i) { 
        d3.select(this)
        .attr("r", 32)
        .style("fill", "orange");
      })
   .on('mouseout', function (d, i) {
        fadeOut();
    })
    .attr("cx", function (d) { return xscale(+d.admit_probability); })
    .attr("cy", function (d) { return yscale(+d.rank); });
   // .ease("elastic");

var text = svg.selectAll(null)
    .data(data)
    .enter()
    .append('text');

var textLabels = text
        .attr("x", function (d) { return xscale(+d.admit_probability); })
        .attr("text-anchor", "middle")
        .attr("y", function (d) { return yscale(+d.rank); })
        .text("Hi")
        .attr("font-family", "sans-serif")
        .attr("font-size", "10px")
        .attr("fill", "red");

svg.append("text")
    .attr("transform", "translate(" + (width / 2) + " ," + (height + margin) + ")")
    .style("text-anchor", "middle")
    .text("Average Acceptance");

svg.append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 0 - margin)
    .attr("x",0 - (height / 2))
    .attr("dy", "1em")
    .style("text-anchor", "middle")
    .text("Rank");

function fadeOut() {
    svg.selectAll("circle")
    .transition()
    .style("opacity", 0.3)
    .attr("r", 20)
    .style("fill", "blue");
}

我该怎么做?

1 个答案:

答案 0 :(得分:1)

解决方案1:

一个简单的解决方案是附加<g>元素来保存文本和圈子:

var group = svg.selectAll(null)
    .data(data)
    .enter()
    .append("g");

group.append("circle")
    //etc...

group.append("text")
    //etc...

然后将事件监听器添加到组中,同时选择文本和圈子:

group.on('mouseover', function(d, i) {
    d3.select(this).select("circle")
        //etc...

    d3.select(this).select("text")
        /etc...
})

以下是这些变化的小提琴:https://jsfiddle.net/p5f0eey1/

解决方案2:

第二种解决方案不涉及任何群体。这就是问题所在:当你想将相同的转换或相同的属性应用于一组元素时,人们会立即想到“我将它们放在一个组元素中”。问题是创建越来越多的SVG元素会降低页面速度。另一方面,这些天脚本可以非常快地运行。因此,您可以依靠脚本来选择所需的文本,只将事件监听器添加到圆圈中。

由于圆圈和文本都具有相同的数据,因此您可以在圆圈的事件处理程序中获取正确的文本:

circles.on('mouseover', function(d, i) {
    d3.select(this)
        .attr("r", 32)
        .style("fill", "orange");

    texts.filter(function(e) {
        return e.rank === d.rank;
    }).attr("font-size", "20px")
})

这是更新的小提琴:https://jsfiddle.net/mtjoxp3a/