d3 Отзывчивая гистограмма

1

Я занимался этим часами и, похоже, не мог вести свою групповую гистограмму. В частности, пытаясь получить правильную ширину для свойства "g" для каждого бара.

Я попробовал несколько методов, и это кажется самым элегантным, хотя я открыт для других решений. Цель состоит в следующем: http://www.cagrimmett.com/til/2016/04/26/responsive-d3-bar-chart.html

var data = [{"category":"Securily Provisions","values":[{"value":50,"rate":"Work Performed"},{"value":40,"rate":"Knowledge, Skills, and Abilities"}]},{"category":"Investigate","values":[{"value":25,"rate":"Work Performed"},{"value":21,"rate":"Knowledge, Skills, and Abilities"}]},{"category":"Operate and Maintain","values":[{"value":3,"rate":"Work Performed"},{"value":22,"rate":"Knowledge, Skills, and Abilities"}]},{"category":"Oversee and Govern","values":[{"value":12,"rate":"Work Performed"},{"value":7,"rate":"Knowledge, Skills, and Abilities"}]},{"category":"Protect and Defend","values":[{"value":6,"rate":"Work Performed"},{"value":15,"rate":"Knowledge, Skills, and Abilities"}]},{"category":"Collect and Operate","values":[{"value":92,"rate":"Work Performed"},{"value":85,"rate":"Knowledge, Skills, and Abilities"}]}]

var margin = {top: 20, right: 20, bottom: 30, left: 40},
  width = 960 - margin.left - margin.right,
  height = 500 ;

var x0 = d3.scale.ordinal().rangeRoundBands([0, width], .5);

var x1 = d3.scale.ordinal();

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

var xAxis = d3.svg.axis()
  .scale(x0)
  .orient("bottom");

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

var color = d3.scale.ordinal()
  .range(["#02bfe7","#fdb81e"]);

var svg = d3.select('#chart-area').append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .attr("preserveAspectRatio", "xMinYMin meet")
  .append("g").attr("class","container")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

//d3.json("data.json", function(error, data) {

  var categoriesNames = data.map(function(d) {
    return d.category;
  });

  var rateNames = data[0].values.map(function(d) {
    return d.rate;
  });

  x0.domain(categoriesNames);
  x1.domain(rateNames).rangeRoundBands([0, x0.rangeBand()]);

  y.domain([0, d3.max(data, function(categorie) {
    return d3.max(categorie.values, function(d) {
      return d.value;
    });
  })]);

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

  svg.append("g")
    .attr("class", "y axis")
    .style('opacity','0')
    .call(yAxis)
    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", ".71em")
    .style("text-anchor", "end")
    .style('font-weight','bold')
    .text("Value");

  svg.select('.y').transition().duration(500).delay(1300).style('opacity','1');

  var slice = svg.selectAll(".slice")
    .data(data)
    .enter().append("g")
    .attr("class", "g")
    .attr("transform",function(d) { return "translate(" + x0(d.category) + ",0)"; });

  slice.selectAll("rect")
    .data(function(d) { return d.values; })
    .enter().append("rect")
    .attr("width", x1.rangeBand())
    .attr("x", function(d) { return x1(d.rate); })
    .style("fill", function(d) { return color(d.rate) })
    .attr("y", function(d) { return y(0); })
    .attr("height", function(d) { return height - y(0); })
    .on("mouseover", function(d) {
      d3.select(this).style("fill", d3.rgb(color(d.rate)).darker(2));
    })
    .on("mouseout", function(d) {
      d3.select(this).style("fill", color(d.rate));
    });

  slice.selectAll("rect")
    .transition()
    .delay(function (d) {return Math.random()*1000;})
    .duration(1000)
    .attr("class","bar")
    .attr("y", function(d) { return y(d.value); })
    .attr("height", function(d) { return height - y(d.value); });

  //Legend
  var legend = svg.selectAll(".legend")
    .data(data[0].values.map(function(d) { return d.rate; }).reverse())
    .enter().append("g")
    .attr("class", "legend")
    .attr("transform", function(d,i) { return "translate(0," + i * 20 + ")"; })
    .style("opacity","0");

  legend.append("rect")
    .attr("x", width - 18)
    .attr("width", 18)
    .attr("height", 18)
    .style("fill", function(d) { return color(d); });

  legend.append("text")
    .attr("x", width - 24)
    .attr("y", 9)
    .attr("dy", ".35em")
    .style("text-anchor", "end")
    .text(function(d) {return d; });

  legend.transition().duration(500).delay(function(d,i){ return 1300 + 100 * i; }).style("opacity","1");

  document.addEventListener("DOMContentLoaded", resize);
  d3.select(window).on('resize', resize);

  function resize() {
    console.log('----resize function----');
    // update width
    width = parseInt(d3.select('#chart-area').style('width'), 10);
    width = width - margin.left - margin.right;

    height = parseInt(d3.select("#chart-area").style("height"));
    height = height - margin.top - margin.bottom;
    console.log('----resiz width----'+width);
    console.log('----resiz height----'+height);
    // resize the chart

    x0.range([0, width]);
    x0.rangeRoundBands([0, width], .03);
    y.range([height, 0]);

    yAxis.ticks(Math.max(height/50, 2));
    xAxis.ticks(Math.max(width/50, 2));

    d3.select(svg.node().parentNode)
      .style('width', (width + margin.left + margin.right) + 'px');

    svg.selectAll('.g')
      //.attr("x", function(d) { return x0(categoriesNames); })
      //.attr("x", function(d) { return x1(d.rate); })
      // Problem here applying new width within translate 
      .attr("transform", "translate(10,0)")
      .attr("width", x1.rangeBand());

    svg.selectAll("text")
      // .attr("x", function(d) { return x0(categoriesNames); })
      .attr("x", (function(d) { return x0(categoriesNames	) + x0.rangeBand() / 2 ; }  ))
      .attr("y", function(d) { return y(rateNames) + 1; })
      .attr("dy", ".75em");

  svg.select('.x.axis').call(xAxis.orient('bottom')).selectAll("text").attr("x",55);


  }
//});
    .bar{
      fill: steelblue;
    }

    .bar:hover{
      fill: brown;
    }

    .axis {
      font: 10px sans-serif;
    }

    .axis path,
    .axis line {
      fill: none;
      stroke: #000;
      shape-rendering: crispEdges;
    }
    #chart-area {width: 100%;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

<div id="chart-area"></div>
Теги:
d3.js
svg

1 ответ

0
Лучший ответ

Вот решение. Это желаемый результат? Попробуйте изменить размер окна.

JS FIDDLE

Функция изменения размера:

function resize() {
console.log('----resize function----');
// update width
width = parseInt(d3.select('#chart-area').style('width'), 10);
width = width - margin.left - margin.right;

height = parseInt(d3.select("#chart-area").style("height"));
height = height - margin.top - margin.bottom;
console.log('----resiz width----'+width);
console.log('----resiz height----'+height);
// resize the chart

    x0.rangeRoundBands([0, width], .5);
x1.domain(rateNames).rangeRoundBands([0, x0.rangeBand()]);
y.range([height, 0]);

yAxis.ticks(Math.max(height/50, 2));
xAxis.ticks(Math.max(width/50, 2));

d3.select(svg.node().parentNode)
  .style('width', (width + margin.left + margin.right) + 'px');

svg.selectAll('.g')
  .attr("transform",function(d) { 
    return "translate(" + x0(d.category) + ",0)"; 
    });
    svg.selectAll('.g').selectAll("rect").attr("width", x1.rangeBand())
    .attr("x", function(d) { return x1(d.rate); })
svg.selectAll(".legend rect")
  .attr("x", width - 18);
svg.selectAll('.legend text')
    .attr("x", width - 24)  
svg.select('.x.axis').call(xAxis.orient('bottom')); 
}

Я внес несколько изменений в функцию изменения размера. Вот почему:

  1. Диапазоны x0 и x1 (оба) должны быть сброшены при изменении размера:
    x0.rangeRoundBands([0,width],.5);
    x1.domain(rateNames).rangeRoundBands([0,x0.rangeBand()]);
    y.range([height, 0]);
    
  2. Перевод (10,0) был принудительным, установленным в функции изменения размера, и вы не можете применить ширину к (группе). В принципе, вам просто нужно вызвать весь код из исходного рендеринга, который включает изменения ширины и высоты. Посмотрите на функцию изменения размера.

  3. Повторная рендеринг оси X внизу содержит статическое значение для x тиков:

svg.select('.x.axis').call(xAxis.orient('bottom')).selectAll("text").attr("x",55);

Просто удалил attr("x", 55)

Надеюсь это поможет. :)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню