D3:根据窗口宽度调整条形图 [英] D3: Resize bar chart according to window width

查看:82
本文介绍了D3:根据窗口宽度调整条形图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个D3条形图,我正在尝试根据浏览器窗口大小调整其宽度。这是图表脚本,其中宽度变量是根据SVG的父div的宽度(#chart1)设置的,其宽度在css中设置:

I have a D3 bar chart and I'm trying to resize its width according to the browser window size. Here is the chart script where the width variable is being set according to the SVG's parent div's width (#chart1), which has a percentage width set in the css:

var $chartWidth= $('#chart1').width();
var margin = {top:20, right:35, bottom:30, left:35};
var height = 180 - margin.top - margin.bottom;
var width = $chartWidth - margin.left - margin.right;
var parseDate = d3.time.format("%m/%Y").parse;

var yScaleBar = d3.scale.linear()
    .domain([0,100])
    .range([height, 0]);    

var xBarScale = d3.scale.ordinal()
    .rangeRoundBands([0, width], .1);   

var yAxisBar = d3.svg.axis()
    .scale(yScaleBar)
    .ticks(4)
    .tickSize(-width, 0, 0)
    .orient("left");        

var xBarAxis = d3.svg.axis()
    .scale(xBarScale)
    .ticks(4)
    .orient("bottom");

var canvasBars = d3.select("#chart1").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 data = [
    {date:"01/2009",bar2:"50",bar:"10",q:"1Q 2009"},
    {date:"04/2009",bar2:"56",bar:"32",q:"2Q"},
    {date:"07/2009",bar2:"57",bar:"70",q:"3Q"},
    {date:"10/2009",bar2:"58",bar:"60",q:"4Q"},
    {date:"01/2010",bar2:"52",bar:"45",q:"1Q '10"}
];

  data.forEach(function(d) {
    d.date = parseDate(d.date);
    d.bar2 = +d.bar2;
    d.bar = +d.bar;
  });

xBarScale.domain(d3.range(data.length));

xBarAxis.tickValues([data[0].q,data[1].q,data[2].q,data[3].q,data[4].q]);  

canvasBars.append("g")
      .attr("class", "xaxis")
      .attr("transform", "translate(0," + height + ")")
      .call(xBarAxis);            


canvasBars.append("g")
      .attr("class", "yaxis")
      .call(yAxisBar); 


canvasBars.selectAll("rect")
                .data(data)
                .enter()
                .append("rect")
                .attr({
                "x": function(d) {return xBarScale(d.date);},  
                "y": function(d) {return yScaleBar(d.bar);},  
                "height": function(d) {return height -yScaleBar(d.bar);},
                "width": xBarScale.rangeBand(),
                "fill": "steelblue"
                }); 

当窗口调整大小时,宽度变量会改变并调用resize();

When the window resizes, the width variable changes and calls resize();

$( window ).resize(function() {
  $chartWidth = $('#chart1').width();
  width = $chartWidth - margin.left - margin.right;
  resize();
});

然后我的调整大小函数应该改变SVG的宽度属性,即yAxisBar刻度线的宽度,和xBarScale rangeRoundBands .....然后我认为我需要选择所有的条(rects)并根据新的xBarScale.rangeRoundBands更改它们的width属性。但我不确定如何正确选择这三件事。到目前为止,只是条形宽度随窗口一起调整 - 但不是刻度线或SVG。这是我尝试过的:

Then my resize function should change the width attribute of the SVG, the width of the yAxisBar tick marks, and the xBarScale rangeRoundBands..... I then think I need to select all the bars (rects) and change their width attributes according the to the new xBarScale.rangeRoundBands. but I'm not sure how to correctly select these 3 things. So far, just the bar width's resize along with the window - but not the tick marks or the SVG. Here is what I've tried:

function resize(){
    canvasBars.attr("width", width + margin.left + margin.right);
        yAxisBar.tickSize(-width, 0, 0);
        xBarScale.rangeRoundBands([0, width], .1);
        canvasBars.selectAll("rect").attr("width", xBarScale.rangeBand());
}


推荐答案

还有更好的方法使用Bootstrap 3框架执行此操作。我已经在网站上实现了这一点,所以我可以告诉你我是如何为我做的,也许你可以根据自己的特定需求进行调整。

There is a much better way to do this with the Bootstrap 3 framework. I'm already implementing that for a website so I can show you how I do it for me and maybe you can adapt it to your specific needs.

HTML代码

<div class="container>
<div class="row">

<div class='col-sm-6 col-md-4' id="month-view" style="height:345px;">
<div id ="responsivetext">Something to write</div>
</div>

</div>
</div>

由于我的需要,我设置了一个固定的高度,但你可以保留 auto 的大小
col-sm-6 col-md-4使div响应。您可以在 http://getbootstrap.com/css/#grid-example-basic

I have set up a fixed height because of my needs, but you can leave the size auto as well. The "col-sm-6 col-md-4" makes the div responsive. You can learn more at http://getbootstrap.com/css/#grid-example-basic

我们可以使用id month-view 的帮助,下面的代码可以在d3.js中实现。

We can access the graph with the help of the id month-view which can be seen below in the following code implemented with d3.js.

用d3做神奇:

    var visualize = function(data){

    // Initialize and select div, get the width and height that you want to use for the bar
    var width = document.getElementById('month-view').offsetWidth;

    var height = document.getElementById('month-view').offsetHeight - document.getElementById('responsivetext2').offsetHeight;



    var total_map = data.map(function (i){ return parseInt(i.total);});


    var heightScale = d3.scale.linear()
                   .domain([0, d3.max(total_map)])
                   .range([0, height-5]);


    var x = d3.scale.ordinal()
          .rangeRoundBands([0, width-30], .1);

    var canvas = d3.select("#month-view").append("svg")
        .attr("width", width - 13)
        .attr("height", height + 20)
        .append("g")
        .attr("transform","translate(5,-20)");

    var div = d3.select("body").append("div")
                      .attr("class", "tooltip")
                      .style("opacity", 0);

    // Add first bar (total)                  
    canvas.selectAll(".bar2")
        .data(data)
        .enter()
        .append('rect')
        .attr('width',  width/12 - 5)
        .attr('height', function (d){return heightScale(d.total)})
        .attr('x', function (d, i) {return i * (width/12 -3 )})
        .attr('y', function (d) {return height + 10 - heightScale(d.total)})
        .attr('class', 'bar2')
        .on("mouseover", function(d) {
          div.transition()
              .duration(200)
              .style("opacity", .95);
          div.html(monthNames(d.month) + "<br/>" + d.total.toFixed(0)+" kr total<br/> <span class='green'>"+ ( (d.total * d.eco)/100  ).toFixed(0) + " kr eko</span>")
              .style("left", (d3.event.pageX - 45) + "px")
              .style("top", (d3.event.pageY - 55) + "px");
          })
        .on("mouseout", function(d) {
            div.transition()
                .duration(500)
                .style("opacity", 0);
        });

    // Add second bar (money)
    canvas.selectAll(".bar")
        .data(data)
        .enter()
        .append('rect')
        .attr('width',  width/12 - 5)
        .attr('height', function (d){ return heightScale(( (d.total * d.eco)/100).toFixed(0))})
        .attr('x', function (d, i) {return i * (width/12 -3 )})
        .attr('y', function (d) {return height + 10 - heightScale(( (d.total * d.eco)/100).toFixed(0) )})
        .attr('class', 'bar')
        .on("mouseover", function(d) {
          div.transition()
              .duration(200)
              .style("opacity", .95);
          div.html(monthNames(d.month) + "<br/>"  + d.total.toFixed(0)+" kr total<br/> <span class='green'>"+ ( (d.total * d.eco)/100).toFixed(0) + " kr eko</span>")
              .style("left", (d3.event.pageX - 45) + "px")
              .style("top", (d3.event.pageY - 55) + "px");
          })
        .on("mouseout", function(d) {
            div.transition()
                .duration(500)
                .style("opacity", 0);
        });

    canvas.append("g")
      .attr("transform", "translate(0,0)");


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

    x.domain(data.map(function(d) { return monthNames(d.month).substring(0, 3); }));


    }

由于你已经在使用d3,我我不会花时间来解释我在这段代码中使用过的所有东西,但它至少是一个有效的代码。你需要的是这个部分:

Since you already are using d3, I won't spend the time to explain everything that I've used in this code, but it's a working code at least. What you need is the part:

    var width = document.getElementById('month-view').offsetWidth;

    var height = document.getElementById('month-view').offsetHeight - document.getElementById('responsivetext2').offsetHeight;

通过获取id为 month-view <的div的宽度来设置宽度/ strong>即可。

The width is set by getting the width of the div with the id month-view.

我的情况下的高度不应该包括整个区域。我在条形图上方也有一些文字,所以我也需要计算这个区域。这就是我用id responsivetext 确定文本区域的原因。为了计算条形的允许高度,我高度中减去 文本高度

The height in my case should not include the entire area. I also have some text above the bar so I need to calculate that area as well. That's why I identified the area of the text with the id responsivetext. For calculating the allowed height of the bar, I subtracted the height of the text from the height of the div.

这允许你有一个采用所有不同屏幕/格尺寸的条形图。

This allows you to have a bar that will adopt all the different screen/div sizes.

这篇关于D3:根据窗口宽度调整条形图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆