d3没有创建足够的元素来匹配我的数据 - 为什么?

时间:2016-05-11 06:04:51

标签: d3.js

所以这里...... http://codepen.io/dwilbank68/pen/VagOKd?editors=0010

我有相同的精确数据数组,创建正确的点数,但没有足够数量的文本元素。

这不是遮挡名称的边际问题......元素甚至不在DOM中。

我甚至将索引附加到名称,以证明graphData数组具有正确数量的元素。

还有什么可能是错的?

svg.selectAll('.dot')               // creates the correct number of dots
    .data(graphData)
    .enter()
      .append('circle')
        .attr('class', 'dot')
        .attr('r', 5)
        .attr('cx', (d)=> xScale(d.secondsBehind) )
        .attr('cy', (d)=> yScale(d.place) )
        .style('fill', (d)=> colorScale(d.dopingAllegations) );

  svg.selectAll('.label')       // does not create the last two text elements 
    .data(graphData)
    .enter()
      .append('text')
        .attr('class', 'label')
        .attr('x', (d)=> xScale(d.secondsBehind) + 10)
        .attr('y', (d)=> yScale(d.place) + 4)
        .text( (d)=> d.name );



var url = "https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/cyclist-data.json";

var m = {t: 20, r: 120, b: 30, l: 40},
    width = 800 - m.l - m.r,
    height = 700 - m.t - m.b;

var svg = d3.select("body").append("svg")
                              .attr("width", width + m.l + m.r)
                              .attr("height", height + m.t + m.b)
                            .append("g")
                              .attr("transform", "translate(" + m.l + "," + m.t + ")");

var div = d3.select('body')
            .append('div')
              .style({
                'position':'absolute',
                'text-align':'center',
                'width':'240px',
                'height':'2.5em',
                'font':'1.5em sans-serif',
                'color':'yellow',
                'background':'black',
                'border-radius':'8px',
                'border':'solid 1px green',
                'opacity':0
              });

var colorScale = d3.scale.ordinal()
                          .range(["#FF0000", "#009933"]);

var xScale = d3.scale.linear()
                .range([width, 0]);

var yScale = d3.scale.linear()
                .range([0, height]);

var xAxis = d3.svg.axis()
                  .scale(xScale)
                  .orient("bottom")
                  .tickFormat(formatMinSec);

var yAxis = d3.svg.axis()
                  .scale(yScale)
                  .orient("left");


d3.json(url, callback);

function callback (error, data) {

    if (error) throw error;

    var bestTime = _.sortBy(data, 'Place')[0].Seconds;
  
    var graphData = _.map(data, (d)=> ({
        'secondsBehind': Math.abs(bestTime - d.Seconds),
        'year': d.Year,
        'nationality': d.Nationality,
        'doping': d.Doping,
        'dopingAllegations': d.Doping.length > 0 ? "Doping Allegations":"No Doping Allegations",
        'name': d.Name,
        'place': d.Place,
        'time': d.Time
    }) )
    
    var timeRange = d3.extent(graphData, (d) => d.secondsBehind );
    
    xScale.domain([timeRange[0]-15, timeRange[1]]);
  
    var rankRange = d3.extent(graphData, (d) => d.place );

    yScale.domain([rankRange[0], rankRange[1]+1]);

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis)
          .append("text")
          .text("Minutes : Seconds Behind Fastest Time")
          .attr({
            'class': 'label',
            'x': width,
            'y': -6
          })
          .style("text-anchor", "end");

    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis)
        .append("text")
          .text("Ranking")
          .attr({
            'class': 'label',
            "transform": "rotate(-90)",
            "y": 6,
            "dy":   ".71em"
          })
          .style("text-anchor", "end");

    svg.selectAll('.dot')
        .data(graphData)
        .enter()
          .append('circle')
            .attr('class', 'dot')
            .attr('r', 5)
            .attr('cx', (d)=> xScale(d.secondsBehind) )
            .attr('cy', (d)=> yScale(d.place) )
            .style('fill', (d)=> colorScale(d.dopingAllegations) );
    
      svg.selectAll('.label')
        .data(graphData)
        .enter()
          .append('text')
            .attr('class', 'label')
            .attr('x', (d)=> xScale(d.secondsBehind) + 10)
            .attr('y', (d)=> yScale(d.place) + 4)
            .text( (d)=> d.name );
  
    // d3.selectAll('.dot')
    //   .on('mouseover', mouseover)
    //   .on('mouseout', mouseout);
  
    var legend = svg.selectAll('.legend')
                    .data(colorScale.domain())
                    .enter()
                      .append('g')
                        .attr('class', 'legend')
                        .attr('transform', function(d,i){return 'translate(0,' +i*20+')';});

    legend.append('rect')
          .attr('x', width)
          .attr('y', 100)
          .attr('width', 18)
          .attr('height', 18)
          .style('fill', colorScale);

    legend.append('text')
          .text((d)=> d)
          .attr('x', width - 18)
          .attr('y', 108)
          .attr('dy', '.35em')
          .style('text-anchor', 'end');

};



// function mouseover(d){
//     div.html('Sepal Width: ' + d.sepalWidth +
//             '<br/>' +
//             'Sepal Length: ' + d.sepalLength)
//       .style('left', (d3.event.pageX + 9) +'px')
//       .style('top', (d3.event.pageY - 43) +'px')
//       .style('opacity', 1);
// }

// function mouseout(){
//     div.style('opacity', 1e-6);
// }

function formatMinSec(d){
    if( d % 60 > 9){
      return Math.floor(d/60) +':'+  d%60
    } else {
      return Math.floor(d/60) +':0'+  d%60
    }
}
&#13;
body {
  font: 10px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.dot {
  stroke: #000;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.min.js"></script>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:1)

而不是:

svg.selectAll('.dot')               // creates the correct number of dots
    .data(graphData)
    .enter()
      .append('circle')
        .attr('class', 'dot')
        .attr('r', 5)
        .attr('cx', (d)=> xScale(d.secondsBehind) )
        .attr('cy', (d)=> yScale(d.place) )
        .style('fill', (d)=> colorScale(d.dopingAllegations) );

  svg.selectAll('.label')       // does not create the last two text elements 
    .data(graphData)
    .enter()
      .append('text')
        .attr('class', 'label')
        .attr('x', (d)=> xScale(d.secondsBehind) + 10)
        .attr('y', (d)=> yScale(d.place) + 4)
        .text( (d)=> d.name );

这样做:

var gs = svg.selectAll('.dot')
    .data(graphData)
    .enter();
      gs.append('circle')
        .attr('class', 'dot')
        .attr('r', 5)
        .attr('cx', (d)=> xScale(d.secondsBehind) )
        .attr('cy', (d)=> yScale(d.place) )
        .style('fill', (d)=> colorScale(d.dopingAllegations) );

  gs
      .append('text')
        .attr('class', 'label')
        .attr('x', (d)=> xScale(d.secondsBehind) + 10)
        .attr('y', (d)=> yScale(d.place) + 4)
        .text( (d)=> { return d.name; } );

工作代码here

其他选项是代替

  svg.selectAll('.label')       // does not create the last two text elements 
    .data(graphData)
    .enter()
      .append('text')
        .attr('class', 'label')
        .attr('x', (d)=> xScale(d.secondsBehind) + 10)
        .attr('y', (d)=> yScale(d.place) + 4)
        .text( (d)=> d.name );

这样做:

  svg.selectAll('.label')
    .data(graphData, function(d) {
      if (d) {
        return d.place; //unique identifier of the data, otherwise Marco Pantani will come only once.
      }
    })
    .enter()
    .append('text')
    .attr('class', 'label')
    .attr('x', (d) => xScale(d.secondsBehind) + 10)
    .attr('y', (d) => yScale(d.place) + 4)
    .text((d) => d.name);

工作代码here

答案 1 :(得分:1)

  • 使用班级label
  • 为您的轴添加两个标签
  • 您的选择svg.selectAll('.label')搜索整个svg并基于.label

选择这两个标签,将它们计算为已经创建的,因此在enter阶段无关紧要

最简单的解决方法是将您的选择包装在g元素中,例如

var graph = svg.append("g");

graph.selectAll('.dot')
     .data(graphData)
     // ...

graph.selectAll('.label')
     .data(graphData)
     // ...

和演示

&#13;
&#13;
var url = "https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/cyclist-data.json";

var m = {t: 20, r: 120, b: 30, l: 40},
    width = 800 - m.l - m.r,
    height = 700 - m.t - m.b;

var svg = d3.select("body").append("svg")
                              .attr("width", width + m.l + m.r)
                              .attr("height", height + m.t + m.b)
                            .append("g")
                              .attr("transform", "translate(" + m.l + "," + m.t + ")");

var div = d3.select('body')
            .append('div')
              .style({
                'position':'absolute',
                'text-align':'center',
                'width':'240px',
                'height':'2.5em',
                'font':'1.5em sans-serif',
                'color':'yellow',
                'background':'black',
                'border-radius':'8px',
                'border':'solid 1px green',
                'opacity':0
              });

var colorScale = d3.scale.ordinal()
                          .range(["#FF0000", "#009933"]);

var xScale = d3.scale.linear()
                .range([width, 0]);

var yScale = d3.scale.linear()
                .range([0, height]);

var xAxis = d3.svg.axis()
                  .scale(xScale)
                  .orient("bottom")
                  .tickFormat(formatMinSec);

var yAxis = d3.svg.axis()
                  .scale(yScale)
                  .orient("left");


d3.json(url, callback);

function callback (error, data) {

    if (error) throw error;

    var bestTime = _.sortBy(data, 'Place')[0].Seconds;
  
    var graphData = _.map(data, (d)=> ({
        'secondsBehind': Math.abs(bestTime - d.Seconds),
        'year': d.Year,
        'nationality': d.Nationality,
        'doping': d.Doping,
        'dopingAllegations': d.Doping.length > 0 ? "Doping Allegations":"No Doping Allegations",
        'name': d.Name,
        'place': d.Place,
        'time': d.Time
    }) )
    
    var timeRange = d3.extent(graphData, (d) => d.secondsBehind );
    
    xScale.domain([timeRange[0]-15, timeRange[1]]);
  
    var rankRange = d3.extent(graphData, (d) => d.place );

    yScale.domain([rankRange[0], rankRange[1]+1]);

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis)
          .append("text")
          .text("Minutes : Seconds Behind Fastest Time")
          .attr({
            'class': 'label',
            'x': width,
            'y': -6
          })
          .style("text-anchor", "end");

    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis)
        .append("text")
          .text("Ranking")
          .attr({
            'class': 'label',
            "transform": "rotate(-90)",
            "y": 6,
            "dy":   ".71em"
          })
          .style("text-anchor", "end");

	 var graph = svg.append("g");

    graph.selectAll('.dot')
        .data(graphData)
        .enter()
          .append('circle')
            .attr('class', 'dot')
            .attr('r', 5)
            .attr('cx', (d)=> xScale(d.secondsBehind) )
            .attr('cy', (d)=> yScale(d.place) )
            .style('fill', (d)=> colorScale(d.dopingAllegations) );
    
      graph.selectAll('.label')
        .data(graphData)
        .enter()
          .append('text')
            .attr('class', 'label')
            .attr('x', (d)=> xScale(d.secondsBehind) + 10)
            .attr('y', (d)=> yScale(d.place) + 4)
            .text( (d)=> d.name );
  
    // d3.selectAll('.dot')
    //   .on('mouseover', mouseover)
    //   .on('mouseout', mouseout);
  
    var legend = svg.selectAll('.legend')
                    .data(colorScale.domain())
                    .enter()
                      .append('g')
                        .attr('class', 'legend')
                        .attr('transform', function(d,i){return 'translate(0,' +i*20+')';});

    legend.append('rect')
          .attr('x', width)
          .attr('y', 100)
          .attr('width', 18)
          .attr('height', 18)
          .style('fill', colorScale);

    legend.append('text')
          .text((d)=> d)
          .attr('x', width - 18)
          .attr('y', 108)
          .attr('dy', '.35em')
          .style('text-anchor', 'end');

};




// function mouseout(){
//     div.style('opacity', 1e-6);
// }

function formatMinSec(d){
    if( d % 60 > 9){
      return Math.floor(d/60) +':'+  d%60
    } else {
      return Math.floor(d/60) +':0'+  d%60
    }
}
&#13;
body {
  font: 10px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.dot {
  stroke: #000;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.min.js"></script>
&#13;
&#13;
&#13;