代码之家  ›  专栏  ›  技术社区  ›  Datacrawler

D3条形图和轴

  •  0
  • Datacrawler  · 技术社区  · 6 年前

    我已经一步一步地创建了一个D3图表。我做了一些修改,使SVG具有响应性。我现在的目标是使条形图更具响应性,以便在屏幕尺寸较小(宽度)时更易于阅读。我把这个片段贴在下面,在页面的底部,我把注意力集中在我认为解决方案是隐藏的部分。

    var data = [
        {"area": "one ", "value": 18000},
        {"area": "Two ", "value": 17000},
        {"area": "three ", "value": 80000},
        {"area": "four ", "value": 55000},
        {"area": "five ", "value": 100000},
        {"area": "six", "value": 50000},
        {"area": "seven", "value": 50000}
    ];
     
      
    var margin = {top: 10, right: 10, bottom: 70, left: 30};
    var width = 1900 - margin.left - margin.right;
    var height = 400 - margin.top - margin.bottom;
              
    
    //A fully-responsive chart area
    var svg = d3.select("#chart-div")
                    .append("svg")
                    .attr("width","100%")
                    .attr("height","500px")
                    .attr("viewBox","0 0 "+
                        (width+margin.left+margin.right)+
                        " "+
                        (height+margin.top+margin.bottom) )
                    .append("g")
                    .attr("transform","translate("+
                        margin.left+","+margin.top+")");
    
    var tooltip = d3.select("body").append("div").attr("class", "toolTip");
      
    var x = d3.scaleLinear().range([0, width]);
    var y = d3.scaleBand().range([height, 0]);
    
    var g = svg.append("g")
    		.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
    
      	data.sort(function(a, b) { return a.value - b.value; });
      
      	x.domain([0, d3.max(data, function(d) { return d.value; })]);
        y.domain(data.map(function(d) { return d.area; })).padding(0.1);
    
        g.append("g")
            .attr("class", "x axis")
           	.attr("transform", "translate(0," + height + ")")
          	.call(d3.axisBottom(x).ticks(5).tickFormat(function(d) { return parseInt(d / 1000); }).tickSizeInner([-height]));
    
        g.append("g")
            .attr("class", "y axis")
            .call(d3.axisLeft(y));
    
        g.selectAll(".bar")
            .data(data)
          .enter().append("rect")
            .attr("class", "bar")
            .attr("x", 0)
            .attr("height", y.bandwidth())
            .attr("y", function(d) { return y(d.area); })
            .attr("width", function(d) { return x(d.value); })
            .on("mousemove", function(d){
                tooltip
                  .style("left", d3.event.pageX - 50 + "px")
                  .style("top", d3.event.pageY - 70 + "px")
                  .style("display", "inline-block")
                  .html((d.area) + "<br>" + "£" + (d.value));
            })
        		.on("mouseout", function(d){ tooltip.style("display", "none");});
    @import url('https://fonts.googleapis.com/css?family=Roboto');
    
    body {
      margin: 15px;
      background-color: #F1F3F3;
      font-family: 'Roboto'!important;
    }
    .bar {
    	fill: #6F257F;
    }
    .axis path,
    .axis line {
      fill: none;
      stroke: #D4D8DA;
      stroke-width: 1px;
      shape-rendering: crispEdges;
    }
    .x path {
    	display: none;
    }
    .toolTip {
    	position: absolute;
      display: none;
      min-width: 80px;
      height: auto;
      background: none repeat scroll 0 0 #ffffff;
      border: 1px solid #6F257F;
      padding: 14px;
      text-align: center;
    }
    
    
    
    .svg-container {
        display: inline-block;
        position: relative;
        width: 100%;
        padding-bottom: 100%; /* aspect ratio */
        vertical-align: top;
        overflow: hidden;
    }
    .svg-content-responsive {
        display: inline-block;
        position: absolute;
        top: 10px;
        left: 0;
    }
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <div id="chart-div" style="width:100%;height:100%;"></div>

    我用以下内容更改了部分代码:

    var parentwidth = $("#chart-div").parent().width(); 
    var margin = {top: 10, right: 10, bottom: 70, left: 30};
    var width = parentwidth - margin.left - margin.right;
    var height = 400 - margin.top - margin.bottom;
    

    我真正得到的是 parentwidth 使用jQuery。

    b) 理想情况下,使条形图具有不同的缩放比例,以便用户可以轻松阅读所有内容(小文本大小是一个问题): enter image description here

    我正在测试下面的函数,但我可能会得到一些与chrome插件相关的错误,以避免交叉源错误。如果以下是最佳解决方案,我可以更新问题:

    function resize() {
      var width = parseInt(d3.select("#chart").style("width")) - margin.left - margin.right,
      height = parseInt(d3.select("#chart").style("height")) - margin.top - margin.bottom;
    
      // Update the range of the scale with new width/height
      xScale.range([0, width]);
      yScale.rangeRoundBands([height, 0], 0.1);
    
      // Update the axis and text with the new scale
      svg.select(".x.axis")
        .call(xAxis)
        .attr("transform", "translate(0," + height + ")")
        .select(".label")
          .attr("transform", "translate(" + width / 2 + "," + margin.bottom / 1.5 + ")");
    
      svg.select(".y.axis")
        .call(yAxis);
    
      // Update the tick marks
      xAxis.ticks(Math.max(width/75, 2), " $");
    
      // Force D3 to recalculate and update the line
      svg.selectAll(".bar")
        .attr("width", function(d) { return xScale(d["total"]); })
        .attr("y", function(d) { return yScale(d["Name"]); })
        .attr("height", yScale.rangeBand());
    };
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   jackdbd    6 年前

    你的问题和我的基本相同 this one

    医生:把你的 <svg> viewBox 属性和a preserveAspectRatio (例如。 xMinYMin meet <svg> 在一个 <div> 那已经 position: relative .

    这不是唯一的解决方案,但它可能是最容易实现和(我认为)最常用的。

    有关其他几种解决方案的概述和讨论,请参阅 this article by Amelia Bellamy-Royds

    另外,要深入了解SVG坐标系,请阅读 this series of articles by Sara Soueidan .

    至于您对jQuery和手机上的文本太小的疑问:

    整个条形图 (即条、轴、标签)向下缩放 向上扩展。这有时叫做 粘性文本 . 你可以看到一个 example here .

        2
  •  0
  •   Datacrawler    6 年前

    var margin = {top: 20, right: 20, bottom: 50, left: 100},
        width = parseInt(d3.select("#chart").style("width")) - margin.left - margin.right,
        height = parseInt(d3.select("#chart").style("height")) - margin.top - margin.bottom;
    
    var yScale = d3.scale.ordinal()
        .rangeRoundBands([height, 0], 0.1);
    
    var xScale = d3.scale.linear()
        .range([0, width]);
    
    var dollarFormatter = d3.format(",.0f")
    
    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient("left");
    
    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient("bottom")
        .tickFormat(function(d) { return "$" + dollarFormatter(d);});
    
    var svg = d3.select("#chart")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
    var tip = d3.tip()
        .attr('class', 'd3-tip')
        .offset([-10, 0])
        .html(function(d) {
          return "<div><span>Name:</span> <span style='color:white'>" + d.Name + "</span></div>" +
                  "<div><span>Sub-Category:</span> <span style='color:white'>" + d["Sub-Category"] + "</span></div>" +
                 "<div><span>Total Sales:</span> <span style='color:white'>" + "$"+ dollarFormatter(d.total) + "</span></div>";
        })
    
    svg.call(tip);
    //Get CSV, JSON from URL
    //var url = "http://bl.ocks.org/josiahdavis/raw/7d84b2f1837eab9c24d9/top.csv";
    
    
    var data = [
      {
        "metric": "Sales",
        "Category": "Furniture",
        "Sub-Category": "Bookcases",
        "Name": "Tom Stivers",
        "total": 1889.8,
        "Type": "Customer"
      },
      {
        "metric": "Sales",
        "Category": "Furniture",
        "Sub-Category": "Bookcases",
        "Name": "Keith Herrera",
        "total": 2020.161,
        "Type": "Customer"
      },
      {
        "metric": "Sales",
        "Category": "Furniture",
        "Sub-Category": "Bookcases",
        "Name": "Jack O'Briant",
        "total": 2122.545,
        "Type": "Customer"
      },
      {
        "metric": "Sales",
        "Category": "Furniture",
        "Sub-Category": "Bookcases",
        "Name": "Nora Paige",
        "total": 2154.9,
        "Type": "Customer"
      },
      {
        "metric": "Sales",
        "Category": "Furniture",
        "Sub-Category": "Bookcases",
        "Name": "Anna Gayman",
        "total": 2396.2656,
        "Type": "Customer"
      },
      {
        "metric": "Sales",
        "Category": "Furniture",
        "Sub-Category": "Bookcases",
        "Name": "Tracy Blumstein",
        "total": 3083.43,
        "Type": "Customer"
      },
      {
        "metric": "Sales",
        "Category": "Furniture",
        "Sub-Category": "Bookcases",
        "Name": "Maribeth Schnelling",
        "total": 3406.664,
        "Type": "Customer"
      },
      {
        "metric": "Sales",
        "Category": "Furniture",
        "Sub-Category": "Bookcases",
        "Name": "Greg Tran",
        "total": 4007.84,
        "Type": "Customer"
      },
      {
        "metric": "Sales",
        "Category": "Furniture",
        "Sub-Category": "Bookcases",
        "Name": "Quincy Jones",
        "total": 4404.9,
        "Type": "Customer"
      },
      {
        "metric": "Sales",
        "Category": "Furniture",
        "Sub-Category": "Bookcases",
        "Name": "Peter Fuller",
        "total": 6232.624,
        "Type": "Customer"
      }];
    
    
    //d3.csv(url, format, function(error, data){
      //if (error) throw error;
    
      // Filter to select a subset
      var subset = data.filter(function(el){
        return  (el["metric"] === "Sales")
                && (el["Sub-Category"] === "Bookcases")
                && (el["Type"] === "Customer");
      });
    
      // Sort the data so bar chart is sorted in decreasing order
      subset = subset.sort(function(a, b) { return a["total"] - b["total"]; });
      console.log(JSON.stringify(subset, null, 2));
    
      yScale.domain(subset.map(function(d) { return d["Name"]; }));
      xScale.domain([0, d3.max(subset, function(d) { return d["total"]; })]);
    
      svg.append("g")
          .attr("class", "y axis")
          .call(yAxis);
    
      svg.append("g")
          .attr("class", "x axis")
          .call(xAxis)
          .attr("transform", "translate(0," + height + ")")
        .append("text")
          .attr("class", "label")
          .attr("transform", "translate(" + width / 2 + "," + margin.bottom / 1.5 + ")")
          .style("text-anchor", "middle")
          .text("Sales");
    
      svg.selectAll(".bar")
          .data(subset)
        .enter().append("rect")
          .attr("class", "bar")
          .attr("width", function(d) { return xScale(d["total"]); })
          .attr("y", function(d) { return yScale(d["Name"]); })
          .attr("height", yScale.rangeBand())
          .on('mouseover', tip.show)
          .on('mouseout', tip.hide);;
    
    //});
    
    // Define responsive behavior
    function resize() {
      var width = parseInt(d3.select("#chart").style("width")) - margin.left - margin.right,
      height = parseInt(d3.select("#chart").style("height")) - margin.top - margin.bottom;
    
      // Update the range of the scale with new width/height
      xScale.range([0, width]);
      yScale.rangeRoundBands([height, 0], 0.1);
    
      // Update the axis and text with the new scale
      svg.select(".x.axis")
        .call(xAxis)
        .attr("transform", "translate(0," + height + ")")
        .select(".label")
          .attr("transform", "translate(" + width / 2 + "," + margin.bottom / 1.5 + ")");
    
      svg.select(".y.axis")
        .call(yAxis);
    
      // Update the tick marks
      xAxis.ticks(Math.max(width/75, 2), " $");
    
      // Force D3 to recalculate and update the line
      svg.selectAll(".bar")
        .attr("width", function(d) { return xScale(d["total"]); })
        .attr("y", function(d) { return yScale(d["Name"]); })
        .attr("height", yScale.rangeBand());
    };
    
    // Call the resize function whenever a resize event occurs
    d3.select(window).on('resize', resize);
    
    // Call the resize function
    resize();
    
    // Define the format function
    function format(d) {
      d.total = +d.total;
      return d;
    }
    @import url('https://fonts.googleapis.com/css?family=Roboto');
    
    body {
      margin: 5px;
      background-color: #F1F3F3;
      font-family: 'Roboto'!important;
    }
    
    .bar {
      fill: #14405F;
    }
    
    .bar:hover {
      fill: #33A1EE;
    }
    
    .axis {
      font: 10px sans-serif;
    }
    
    .axis path,
    .axis line {
      fill: none;
      stroke: #D4D8DA;
      stroke-width: 1px;
      shape-rendering: crispEdges;
    }
    .x path {
    	display: none;
    }
    
    #chart {
      width: 100%;
      height: 100%;
      position: absolute;
    }
    
    .d3-tip {
      line-height: 1;
      font: 14px sans-serif;
      padding: 12px;
      background: rgba(0, 0, 0, 0.8);
      color: rgb(185, 185, 185);
      border-radius: 2px;
    }
    
    /*
    .toolTip {
    	position: absolute;
      display: none;
      min-width: 80px;
      height: auto;
      background: none repeat scroll 0 0 #ffffff;
      border: 1px solid #6F257F;
      padding: 14px;
      text-align: center;
    }
    */
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
    <script src="https://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
    
    
    <svg id="chart"></svg>