dc.js - 响应式 dc.js 图表占据了整个窗口

标签 dc.js

我在使图表响应时遇到问题,我尝试将相同的示例应用于 DC.js 和 Crossfilter(位于此链接):resizing-series .

图表是响应式的,但是,与我拥有的表格交互时存在一些错误。例如,当我单击图表或任何表格时,图表变得非常大,占据整个屏幕。如下图所示:

enter image description here enter image description here

当我使用 Console 分开屏幕时,图表会响应式地呈现,当我更改屏幕尺寸时,图表的大小也会发生变化,但是,如果我离开Console 图形仍然占据整个屏幕,并且不会返回到第一张图像中显示的默认初始大小。

enter image description here enter image description here

有谁知道如何告诉我如何修复这些错误?我不明白为什么会发生这种情况。

提前致谢。

var composite = dc.compositeChart('#composite');
var vendedorTable = dc.dataTable("#vendedores");
var citiesTable = dc.dataTable("#cities");

function remove_empty_bins(source_group) {
  return {
    top: function(N) {
      return source_group.all().filter(function(d) {
        return d.value.totalAno > 1e-3 ||
          d.value.totalHomologo > 1e-3;
      }).slice(0, N);
    }
  };
}

var url = 'https://gist.githubusercontent.com/bernalvinicius/3cece295bc37de1697e7f83418e7fcc9/raw/a5820379ec6eae76ee792495cc5dd1685c977a73/vendedores.json';
d3.json(url).then(function(data) {

  data.forEach(d =>
    Object.assign(d, {
      mes: d.Month,
      atual: d.Vendas_Ano,
      passado: d.Vendas_Ant
    })
  );
  var cf = crossfilter(data);

  vendedorDim = cf.dimension(function(d) {
    return d.vendnm;
  });
  var vendedorGroup = vendedorDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);

  citiesDim = cf.dimension(function(d) {
    return d.zona;
  });
  var citiesGroup = citiesDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);

  var dim = cf.dimension(dc.pluck('mes')),
    grp1 = dim.group().reduceSum(dc.pluck('atual')),
    grp2 = dim.group().reduceSum(dc.pluck('passado'));
  var minMonth = dim.bottom(1)[0].mes;
  var maxMonth = dim.top(1)[0].mes;

  var all = cf.groupAll();

  dc.dataCount(".dc-data-count")
    .dimension(cf)
    .group(all);

  function reduceAdd(p, v) {
    p.totalAno += +v.Vendas_Ano;
    p.totalHomologo += +v.Vendas_Ant;
    return p;
  }

  function reduceRemove(p, v) {
    p.totalAno -= v.Vendas_Ano;
    p.totalHomologo -= v.Vendas_Ant;
    return p;
  }

  function reduceInitial() {
    return {
      totalAno: 0,
      totalHomologo: 0,
    };
  }

  // Fake Dimension
  rank = function(p) {
    return ""
  };

  // Chart by months
  composite
    .width(600)
    .height(300)
    .x(d3.scaleLinear().domain([1, 12]))
    .yAxisLabel("")
    .xAxisLabel("Month")
    .legend(dc.legend().x(500).y(0).itemHeight(13).gap(5))
    .renderHorizontalGridLines(true)
    .compose([
      dc.lineChart(composite)
      .dimension(dim)
      .colors('steelblue')
      .group(grp1, "Currently Year"),
      dc.lineChart(composite)
      .dimension(dim)
      .colors('darkorange')
      .group(grp2, "Last Year")
    ])
    .brushOn(true);

  composite.brush().extent([-0.5, data.length + 1.5])
  composite.extendBrush = function(brushSelection) {
    if (brushSelection) {
      vendedorTable.filter(null);
      vendedorDim.filter(null);
      citiesTable.filter(null);
      citiesDim.filter(null);
      const point = Math.round((brushSelection[0] + brushSelection[1]) / 2);
      return [
        point - 0.5,
        point + 0.5
      ];
    }
  };

  // Sales Table
  vendedorTable.width(500)
    .height(480)
    .dimension(remove_empty_bins(vendedorGroup))
    .group(rank)
    .columns([function(d) {
        return d.key;
      },
      function(d) {
        return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
          minimumFractionDigits: 2
        }) + '€';
      },
      function(d) {
        return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
          minimumFractionDigits: 2
        }) + '€';
      }
    ])
    .sortBy(function(d) {
      return d.value.totalAno
    })
    .order(d3.descending)

  // Cities Table
  citiesTable.width(500)
    .height(480)
    .dimension(remove_empty_bins(citiesGroup))
    .group(rank)
    .columns([function(d) {
        return d.key;
      },
      function(d) {
        return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
          minimumFractionDigits: 2
        }) + '€';
      },
      function(d) {
        return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
          minimumFractionDigits: 2
        }) + '€';
      }
    ])
    .sortBy(function(d) {
      return d.value.totalAno
    })
    .order(d3.descending)

  // Sales click events
  vendedorTable.on('pretransition', function(table) {
    table.selectAll('td.dc-table-column')
      .on('click', function(d) {
        let filters = table.filters().slice();
        if (filters.indexOf(d.key) === -1)
          filters.push(d.key);
        else
          filters = filters.filter(k => k != d.key);
        if (filters.length === 0)
          vendedorDim.filter(null);
        else
          vendedorDim.filterFunction(function(d) {
            return filters.indexOf(d) !== -1;
          })
        table.replaceFilter([filters]);

        citiesTable.filter(null);
        citiesDim.filter(null);
        composite.filter(null);

        dc.redrawAll();
      });
    let filters = table.filters();
    table.selectAll('tr.dc-table-row')
      .classed('sel-rows', d => filters.indexOf(d.key) !== -1);
  });

  // Cities click events
  citiesTable.on('pretransition', function(table) {
    table.selectAll('td.dc-table-column')
      .on('click', function(d) {
        let filters = table.filters().slice();
        if (filters.indexOf(d.key) === -1)
          filters.push(d.key);
        else
          filters = filters.filter(k => k != d.key);
        if (filters.length === 0)
          citiesDim.filter(null);
        else
          citiesDim.filterFunction(function(d) {
            return filters.indexOf(d) !== -1;
          })
        table.replaceFilter([filters]);

        vendedorTable.filter(null);
        vendedorDim.filter(null);
        composite.filter(null);

        dc.redrawAll();
      });
    let filters = table.filters();
    table.selectAll('tr.dc-table-row')
      .classed('sel-rows', d => filters.indexOf(d.key) !== -1);
  });


  dc.renderAll();

  // reset functions
  $('#reset').on('click', function() {
    vendedorTable.filter(null);
    vendedorDim.filter(null);
    citiesTable.filter(null);
    citiesDim.filter(null);
    composite.filter(null);

    dc.redrawAll();
  });

  $('#resetTable').on('click', function() {
    vendedorTable.filter(null);
    vendedorDim.filter(null);
    citiesTable.filter(null);
    citiesDim.filter(null);
    composite.filter(null);

    dc.redrawAll();
  });

  $('#resetTable2').on('click', function() {
    vendedorTable.filter(null);
    vendedorDim.filter(null);
    citiesTable.filter(null);
    citiesDim.filter(null);
    composite.filter(null);

    dc.redrawAll();
  });


  /****************************************************************************/
  // Functions to handle responsive

  var adjustX = 10,
    adjustY = 40;

  apply_resizing(composite, adjustX, adjustY, function(composite) {
    composite.legend().x(window.innerWidth - 200);
  });

  var find_query = function() {
    var _map = window.location.search.substr(1).split('&').map(function(a) {
      return a.split('=');
    }).reduce(function(p, v) {
      if (v.length > 1)
        p[v[0]] = decodeURIComponent(v[1].replace(/\+/g, " "));
      else
        p[v[0]] = true;
      return p;
    }, {});
    return function(field) {
      return _map[field] || null;
    };
  }();

  var resizeMode = find_query('resize') || 'widhei';

  function apply_resizing(composite, adjustX, adjustY, onresize) {
    if (resizeMode === 'viewbox') {
      composite
        .width(300)
        .height(200)
        .useViewBoxResizing(true);
      d3.select(composite.anchor()).classed('fullsize', false);
    } else {
      adjustX = adjustX || 0;
      adjustY = adjustY || adjustX || 0;
      composite
        .width(window.innerWidth - adjustX)
        .height(window.innerHeight - adjustY);
      window.onresize = function() {
        if (onresize) {
          onresize(composite);
        }
        composite
          .width(window.innerWidth - adjustX)
          .height(window.innerHeight - adjustY);

        if (composite.rescale) {
          composite.rescale();
        }
        composite.redraw();
      };
    }
  }
});
#composite {
  padding: 10px;
}

.dc-table-group {
  visibility: collapse;
}

tr.dc-table-row.sel-rows {
  background-color: lightblue;
}

.brush .custom-brush-handle {
  display: none;
}
<!-- favicon -->
<link rel="shortcut icon" href="https://img.icons8.com/nolan/64/puzzle.png">
<!-- bootstrap.css -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- bootstrap-theme.css -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- dc.css -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dc/2.1.8/dc.css">
<!-- jquery.js -->
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
<!-- bootstrap.js -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<!-- d3.v5.js -->
<script src="https://d3js.org/d3.v5.js"></script>
<!-- crossfilter.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
<!-- dc.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/dc/3.1.8/dc.js"></script>

<title>12</title>
</head>

<body>
  <div class="container-fluid">
    <div class="row content">
      <div class="col-md-10">
        <div class="col-md-4">
          <div id="composite"></div>
        </div>
      </div>
    </div>
    <div class="row content">
      <div class="col-md-10">
        <div style="padding: 20px;;" class="row marginClass">
          <h4 class="pull-left" id="Introduction">
            <small>Fictitious company data | Drilldown Example |</small>
          </h4>
          <h6 class="dc-data-count" style="float: left;margin-left:5px;">
            <span>
                            <span class="filter-count"></span> selected from
            <span class="total-count"></span> records |
            <a id="reset"> Reset </a>
            </span>
          </h6>
        </div>

        <div class="col-md-4">
          <table class="table" id="vendedores">
            <thead>
              <tr>
                <th>Sales</th>
                <th>Current Year</th>
                <th>Last Year</th>
              </tr>
            </thead>
          </table>
        </div>

        <div class="col-md-4">
          <table class="table" id="cities">
            <thead>
              <tr>
                <th>City</th>
                <th>Current Year</th>
                <th>Last Year</th>
              </tr>
            </thead>
          </table>
        </div>
      </div>
    </div>
  </div>
</body>

最佳答案

感谢您发布示例!除非您进入全页模式,否则该错误不会显示在 SO 代码片段功能中。我发现your fiddle更容易合作。

注意:这是对我之前的答案的完全重写,这个答案不清楚。

1。使用ResizeObserver

更新于 2020 年 4 月 28 日

从 Safari 13.1(2020 年 3 月 24 日发布)开始,所有现代浏览器都支持 ResizeObserver 。这是检测图表大小调整的最简洁的方法。

我推荐

  1. 使用自上而下的布局(例如 Flexbox 或网格)来定位图表的 div
  2. 使用ResizeObserver确定 div 何时更改大小
  3. 告诉图表使用 .width(null).height(null) 检测图表 div 大小

目前有one resizing example就是这样做的。

特殊值null告诉图表使 SVG 节点与其父 div 大小相同:

chart1.width(null)
    .height(null)

回调使用辅助函数来禁用转换,因为转换只会减慢调整大小并使其看起来笨重:

const callback = chart => entries => {
    redraw_chart_no_transitions(
        chart
            .width(null)
            .height(null)
            .rescale());
    };

设置观察者看起来像

new ResizeObserver(callback(chart1)).observe(d3.select('#test1').node());

请参阅示例了解更多详细信息。

2。使用window.onresize

其他resizing examples关注window.onresize因为直到最近,这是唯一有效、可靠的跨浏览器检测更改的方法。

它们根据窗口大小计算图表大小,如果您的布局是自下而上的,例如使用默认的float: left布局。

这是设置此功能的函数:

function apply_resizing(chart, adjustX, adjustY, onresize) {
    if(!Array.isArray(chart))
        chart = [chart];
    if(!isNaN(adjustX))
        adjustX = (dx => x => x-dx)(adjustX);
    adjustX = adjustX || (x => x);
    if(!isNaN(adjustY))
        adjustY = (dy => y => y-dy)(adjustY);
    adjustY = adjustY || adjustX || (y => y);
    chart.forEach(c => c.width(adjustX(window.innerWidth))
                  .height(adjustY(window.innerHeight)));
    window.onresize = function () {
        if (onresize) {
            chart.forEach(onresize);
        }
        chart.forEach(c => {
            c.width(adjustX(window.innerWidth))
                .height(adjustY(window.innerHeight));
            if (c.rescale) {
                c.rescale();
            }
        });
        redraw_chart_no_transitions(chart);
    };
}

单个图表可以像这样初始化:

apply_resizing(chart, 20);

这会填充窗口,但会使图表宽度减少 20 像素。

该函数还可以在数组中获取多个图表,并调整函数以支持复杂的布局,例如两个图表应垂直分割窗口的布局:

apply_resizing([heatmapChart, barChart], 20, y => y/2-fudge);

关于dc.js - 响应式 dc.js 图表占据了整个窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60279265/

相关文章:

javascript - 隐藏表行所需的帮助 - dc.js

javascript - 对聚合结果进行交叉过滤

javascript - dc.js 百分比直方图 - 组的大小

d3.js - 在 dc.js + labelColors 中向饼图切片添加边框

javascript - 使用 dc.js 进行简单列表过滤器和搜索过滤器?

d3.js - 如何在呈现图表后为 dc.js 图表应用工具提示

javascript - 选择要在 dc.js 条形图中显示的图例名称

javascript - dc.js - 在一组中一起渲染两个对象(一个图表 - 渲染,一个形状 - 不渲染)?

charts - dc.js onClick 监听器不工作

d3.js - dc.js 折线图不显示任何内容