使用d3根据数据附加彩色圆圈

时间:2015-07-11 00:56:48

标签: javascript d3.js svg

我有如下的SVG结构:

<g class="labels"></g>

还有一些d3代码:

// svg is d3 context
var labels = svg.select('.labels');

ca = labels.append('g');

function resize() {
    ca
        .call(colorAxis) // an instance of d3.svg.axis() using same data as below
        .selectAll('text')
            .remove();

    ca
        .selectAll('.tick').select('circle')
            .data(data)
        .enter().append('circle')
            .style('fill', function (datum) {
                return '#' + datum.hex;
            })
            .attr('r', '7.5');
}

结构最终看起来像这样:

<g class="labels">
    <!-- from ca.call(colorAxis) -->
    <g>
        <g class="tick" transform="translate(0,14.285714285714285)" style="opacity: 1;">
            <line x2="-6" y2="0"></line>
        </g>
        <!-- more of these... -->
    </g>
    <circle r="7.5" style="fill: rgb(44, 149, 210);"></circle>
    <!-- as many of these as there are ticks -->
</g>

每次调用调整大小时,它都会添加更多的圆圈(这不是我想要的)。我想要的是这样的结构:

<g class="labels">
    <!-- from ca.call(colorAxis) -->
    <g>
        <g class="tick" transform="translate(0,14.285714285714285)" style="opacity: 1;">
            <line x2="-6" y2="0"></line>
            <circle r="7.5" style="fill: rgb(44, 149, 210);"></circle>
        </g>
        <!-- more of these... -->
    </g>
</g>

如何修复我的d3代码来实现这一目标?我也尝试将ca.selectAll('.tick').select('circle')更改为ca.selectAll('.tick'),这导致圈子根本不会被追加。

编辑我认为这是隐含的,但显然不是。在调整DOM大小时调用resize()函数,并且必须相应地调整轴以适合分配的空间内的内容。数据本身不是动态的。

2 个答案:

答案 0 :(得分:0)

我明白了。我需要将resize()中的代码更改为:

function resize() {
    ca
        .call(colorAxis) // an instance of d3.svg.axis() using same data as below
        .selectAll('text')
            .remove();

    ca
        .selectAll('.tick')
            .data(data)
        .append('circle')
            .style(function (datum) {
                return '#' + datum.hex;
            })
            .attr('r', '7.5');
}

答案 1 :(得分:0)

正如评论中所提到的那样,只要了解了必须调用轴并且(希望)轴布局改变了所有的标记,在调用{之间',@帕特里克提供的解决方案是很好的。 {1}}。原因是每次调用例程时都不会删除现有的圆圈。

即使在更新之间调用轴 ,如果刻度线的数量没有改变 - 例如,如果只有刻度线的颜色编码发生变化 - 那么圆圈将会与每次更新。

对此用例使用@Patricks方法......

 function onZoom(){
    gXaxis.call(xAxis);
    var update = gXaxis.selectAll('.tick')
      .data(x.ticks(xAxis.ticks()[0]))
      .insert('circle', "line")
      .attr('r', 7.5)
      .attr('cy',function(){return 16 + i})
      .style( "fill", function () {
        return cr();
      });
    i++;
    function cr(){
      return d3.scale.category20().range()[Math.round(Math.random()*20)]
    }
  }

工作演示:

&#13;
&#13;
var margin = {
    top: 20,
    right: 20,
    bottom: 30,
    left: 30
  },
  width = 600 - margin.left - margin.right,
  height = 50 - margin.top - margin.bottom;

var x = d3.scale.linear()
  .range([0, width])
  .domain([0, 100]),
  zoom = d3.behavior.zoom()
  .scaleExtent([0.5, 3])
  .on("zoom", onZoom);

var xAxis = d3.svg.axis()
  .scale(x)
  .orient("bottom")
  .ticks(10);

var svg = d3.select("#viz").append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .call(zoom)
  .append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")"),
  gXaxis = svg.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + height + ")");
var i = 0;

function onZoom() {
  gXaxis.call(xAxis);
  var update = gXaxis.selectAll('.tick')
    .data(x.ticks(xAxis.ticks()[0]))
    .insert('circle', "line")
    .attr('r', 7.5)
    .attr('cy', function() {
      return 16 + i
    })
    .style("fill", function() {
      return cr();
    });
  i++;

  function cr() {
    return d3.scale.category20().range()[Math.round(Math.random() * 20)]
  }
}
onZoom();
&#13;
svg {
  outline: 1px solid red;
  overflow: visible;
}
.domain,
.tick line {
  fill: none;
  stroke: black;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="viz">
  <div>scroll to update...</div>
</div>
&#13;
&#13;
&#13;

然而,解决这个问题并不是那么直截了当,你需要添加更多代码......不要太多:

  function onZoom(){
    gXaxis.call(xAxis);
    var update = gXaxis
      .datum(x.ticks(xAxis.ticks()[0]))
      .selectAll('.tick')
      .data(function(d){
        return d
      })
      .selectAll('circle')
      .data(function(d){
        return [d]
      });
      update.enter().insert('circle', "line")
      .attr('r', 7.5)
      .attr('cy',function(){return 16 + i});
    update.style( "fill", function (d, i, j) {
      return cr() ;
    })
    i++;
    function cr(){
      return d3.scale.category20().range()[Math.round(Math.random()*20)]
    }
  }

相同用例的工作演示:

&#13;
&#13;
var margin = {
    top: 20,
    right: 20,
    bottom: 30,
    left: 30
  },
  width = 600 - margin.left - margin.right,
  height = 50 - margin.top - margin.bottom;

var x = d3.scale.linear()
  .range([0, width])
  .domain([0, 100]),
  zoom = d3.behavior.zoom()
  .scaleExtent([0.5, 3])
  .on("zoom", onZoom);

var xAxis = d3.svg.axis()
  .scale(x)
  .orient("bottom")
  .ticks(10);

var svg = d3.select("#viz").append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .call(zoom)
  .append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")"),
  gXaxis = svg.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + height + ")");
var i = 0;

function onZoom() {
  gXaxis.call(xAxis);
  var update = gXaxis
    .datum(x.ticks(xAxis.ticks()[0]))
    .selectAll('.tick')
    .data(function(d) {
      return d
    })
    .selectAll('circle')
    .data(function(d) {
      return [d]
    });
  update.enter().insert('circle', "line")
    .attr('r', 7.5)
    .attr('cy', function() {
      return 16 + i
    });
  update.style("fill", function(d, i, j) {
    return cr();
  })
  i++;

  function cr() {
    return d3.scale.category20().range()[Math.round(Math.random() * 20)]
  }
}
onZoom();
&#13;
svg {
  outline: 1px solid red;
  overflow: visible;
}
.domain,
.tick line {
  fill: none;
  stroke: black;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="viz">
  <div>scroll to update...</div>
</div>
&#13;
&#13;
&#13;