且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在数据表中添加行 - DC.js

更新时间:2023-12-01 20:01:58

dc.js 是 crossfilter 的前端,它是一个用于 JavaScript 的内存数据库,针对此类仪表板进行了调整.

您总是希望在数据库端添加数据.所以正确的地方是在 crossfilter API 中,这里是:crossfilter.add()

我可能刚刚发表了评论,但既然你已经足够好,可以包含运行代码,让我们试试吧!

首先,让我们从数据集中保留一个供应商:

 rows = data0.filter(d => d.vendnm === 'JOÃO LUIS');var data = data0.filter(d => d.vendnm !== 'JOÃO LUIS');

然后,当点击 Add Row 按钮时,让我们添加该数据并重新绘制所有关联的图表:

 $('#addRow').on('click', function() {myCrossfilter.add(行);dc.redrawAll();});

请注意,如果您多次单击添加行",该供应商的销售额将翻一番,然后是三倍,因为我们显示的是一个聚合组,因此该供应商获得的销售额越来越多.

仅此而已!

var vendedorTable = dc.dataTable("#Vendedores");//提升 crossfilter 和 row 以便它们对 addRow 处理程序可见var myCrossfilter,行;var url = 'http://www.json-generator.com/api/json/get/cgsUhkPSjS?indent=2';d3.json(url).then(function(data0) {//保存 Joao 以备后用rows = data0.filter(d => d.vendnm === 'JOÃO LUIS');var data = data0.filter(d => d.vendnm !== 'JOÃO LUIS');data.forEach(函数(d){myCrossfilter = 交叉过滤器(数据);var all = myCrossfilter.groupAll();dc.dataCount(".dc-data-count").dimension(myCrossfilter).组(全部);vendorDim = myCrossfilter.dimension(function(d) {返回 d.vendnm;});var vendedorGroup = vendedorDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);函数减少添加(p,v){p.totalAno += +v.Vendas_Ano;p.totalHomologo += +v.Vendas_Ant;返回 p;}函数减少删除(p,v){p.totalAno -= v.Vendas_Ano;p.totalHomologo -= v.Vendas_Ant;返回 p;}函数 reduceInitial() {返回 {总Ano:0,totalHomologo: 0,};}//格式化程序 = d3.format(".3s");//formatter2 = d3.format(".0%");//假维度排名=函数(p){返回 ""};功能检查行(d){if (d.value.totalAno <= 0 || isNaN(d.value.totalAno) || d.value.totalHomologo <= 0 || isNaN(d.value.totalHomologo)) {返回0;}返回 d;}//供应商表vendorTable.width(500).高度(480).dimension(供应商组).group(排名).columns([函数(d){d = checkRows(d);而(d!= 0){返回 d.key;}},功能(d){d = checkRows(d);而(d!= 0){return Number(Math.round(d.value.totalAno * 100)/100).toLocaleString("es-ES", {最小分数位数:2}) + '€';}},功能(d){d = checkRows(d);而(d!= 0){return Number(Math.round(d.value.totalHomologo * 100)/100).toLocaleString("es-ES", {最小分数位数:2}) + '€';}}]).sortBy(函数(d){返回 d.value.totalAno}).order(d3.descending)vendorTable.on('pretransition', function(table) {table.selectAll('td.dc-table-column').on('点击',函数(d) {让过滤器 = table.filters().slice();if (filters.indexOf(d.key) === -1)过滤器.push(d.key);别的过滤器 = filters.filter(k => k != d.key);if (filters.length === 0)vendorDim.filter(null);别的vendorDim.filterFunction(function(d) {返回过滤器.indexOf(d) !== -1;})table.replaceFilter([过滤器]);dc.redrawAll();});让过滤器 = table.filters();table.selectAll('tr.dc-table-row').classed('sel-rows', d => filters.indexOf(d.key) !== -1);});dc.renderAll();});$('#reset').on('点击', function() {vendorTable.filter(null);vendorDim.filter(null)dc.redrawAll();});$('#resetTable').on('click', function() {vendorTable.filter(null);vendorDim.filter(null)dc.redrawAll();});$('#addRow').on('click', function() {myCrossfilter.add(行);dc.redrawAll();});});

<head><风格>.dc 表组 {可见性:崩溃;}tr.dc-table-row.sel-rows {背景颜色:浅蓝色;}</风格><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><链接 rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" 完整性="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"><link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" 完整性="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"><script src="https://code.jquery.com/jquery-3.4.1.js" 完整性="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="crossorigin="anonymous"></script><script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" 完整性="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dc/2.1.8/dc.css"><script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script><script src="https://d3js.org/d3.v5.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/dc/3.1.8/dc.js"></script><title>供应商</title></头><身体><div class="容器流体"><div class="行内容"><div class="col-md-8" style="padding-left: 20px;"><div class="行边距类"><h4 class="pull-left" id="Introduction"><small>Dados fictícios da empresa |例子德塔哈达 |</small></h4><h6 class="dc-data-count" style="float: left;margin-left:5px;"><跨度><span class="filter-count"></span>从中选出<span class="total-count"></span>记录 |<a id="重置">全部重置 </a></span></h6></div>
<a id="addRow">添加行 </a></div><div class="col-md-6"><br><a id="resetTable">重置</a><table class="table" id="Vendores"><头><tr><th>销售</th><th>当年</th><th>去年</th></tr></头></表></div></div></div></div></body>

I have a json file that loads sales data for salespeople based on the current year and the previous year.

I created a table in which I show the total sales for each year for each salesperson and, in the last row, I need to load the total for all salespeople added up. As shown in the image below:

I am using dc.dataTable to create my table.

Can you tell me if there is any way in DC.js to create a row in my table to put the total sales?

Here is my code, thank you in advance.

var vendedorTable = dc.dataTable("#Vendedores");

var url = 'http://www.json-generator.com/api/json/get/cgsUhkPSjS?indent=2';
d3.json(url).then(function(data) {

  data.forEach(function(d) {

    var myCrossfilter = crossfilter(data);
    var all = myCrossfilter.groupAll();

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

    vendedorDim = myCrossfilter.dimension(function(d) {
      return d.vendnm;
    });

    var vendedorGroup = vendedorDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);

    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,
      };
    }

    // formatter = d3.format(".3s");
    // formatter2 = d3.format(".0%");

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

    function checkRows(d) {
      if (d.value.totalAno <= 0 || isNaN(d.value.totalAno) || d.value.totalHomologo <= 0 || isNaN(d.value.totalHomologo)) {
        return 0;
      }
      return d;
    }

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

    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]);
          dc.redrawAll();
        });
      let filters = table.filters();
      table.selectAll('tr.dc-table-row')
        .classed('sel-rows', d => filters.indexOf(d.key) !== -1);
    });

    dc.renderAll();

  });

  $('#reset').on('click', function() {
    vendedorTable.filter(null);
    vendedorDim.filter(null)

    dc.redrawAll();
  });

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

    dc.redrawAll();
  });

});

<head>
  <style>
    .dc-table-group {
      visibility: collapse;
    }
    
    tr.dc-table-row.sel-rows {
      background-color: lightblue;
    }
  </style>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
  <script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dc/2.1.8/dc.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
  <script src="https://d3js.org/d3.v5.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/dc/3.1.8/dc.js"></script>

  <title>Vendedores</title>
</head>

<body>


  <div class="container-fluid">
    <div class="row content">
      <div class="col-md-8" style="padding-left: 20px;">
        <div class="row marginClass">
          <h4 class="pull-left" id="Introduction"><small>Dados fictícios da empresa | Exemplo de Pesquisa
                            Detalhada |
                        </small></h4>
          <h6 class="dc-data-count" style="float: left;margin-left:5px;">
            <span>
                            <span class="filter-count"></span> selected out of
            <span class="total-count"></span> records |
            <a id="reset"> Reset All </a>
            </span>
          </h6>
        </div>

        <div class="col-md-6">
          <br>
          <a id="resetTable"> Reset</a>
          <table class="table" id="Vendedores">
            <thead>
              <tr>
                <th>Sales</th>
                <th>Current Year</th>
                <th>Last Year</th>
              </tr>
            </thead>
          </table>
        </div>
      </div>
    </div>
  </div>
</body>

dc.js is the frontend for crossfilter, which is an in-memory database for JavaScript that is tuned for these kinds of dashboards.

You always want to add data on the database side. So the right place to look is in the crossfilter API, and here it is: crossfilter.add()

I might have just left a comment, but since you were nice enough to include running code, let's try it out!

First, let's reserve one of the vendors out of the dataset:

  rows = data0.filter(d => d.vendnm === 'JOÃO LUIS');
  var data = data0.filter(d => d.vendnm !== 'JOÃO LUIS');

Then, when the Add Row button is clicked, let's add that data and redraw all the associated charts:

  $('#addRow').on('click', function() {
    myCrossfilter.add(rows);
    dc.redrawAll();
  });

Notice that if you click Add Row multiple times, the sales for that vendor will double, then triple, because we are displaying an aggregated group, so that vendor gets more and more sales added in.

That's all there is to it!

var vendedorTable = dc.dataTable("#Vendedores");
// lift crossfilter and row so they are visible to addRow handler
var myCrossfilter, rows;

var url = 'http://www.json-generator.com/api/json/get/cgsUhkPSjS?indent=2';
d3.json(url).then(function(data0) {

  // save Joao for later
  rows = data0.filter(d => d.vendnm === 'JOÃO LUIS');
  var data = data0.filter(d => d.vendnm !== 'JOÃO LUIS');

  data.forEach(function(d) {

    myCrossfilter = crossfilter(data);
    var all = myCrossfilter.groupAll();

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

    vendedorDim = myCrossfilter.dimension(function(d) {
      return d.vendnm;
    });

    var vendedorGroup = vendedorDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);

    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,
      };
    }

    // formatter = d3.format(".3s");
    // formatter2 = d3.format(".0%");

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

    function checkRows(d) {
      if (d.value.totalAno <= 0 || isNaN(d.value.totalAno) || d.value.totalHomologo <= 0 || isNaN(d.value.totalHomologo)) {
        return 0;
      }
      return d;
    }

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

    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]);
          dc.redrawAll();
        });
      let filters = table.filters();
      table.selectAll('tr.dc-table-row')
        .classed('sel-rows', d => filters.indexOf(d.key) !== -1);
    });

    dc.renderAll();

  });

  $('#reset').on('click', function() {
    vendedorTable.filter(null);
    vendedorDim.filter(null)

    dc.redrawAll();
  });

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

    dc.redrawAll();
  });

  $('#addRow').on('click', function() {
    myCrossfilter.add(rows);
    dc.redrawAll();
  });

});

<head>
  <style>
    .dc-table-group {
      visibility: collapse;
    }
    
    tr.dc-table-row.sel-rows {
      background-color: lightblue;
    }
  </style>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
  <script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dc/2.1.8/dc.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
  <script src="https://d3js.org/d3.v5.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/dc/3.1.8/dc.js"></script>

  <title>Vendedores</title>
</head>

<body>


  <div class="container-fluid">
    <div class="row content">
      <div class="col-md-8" style="padding-left: 20px;">
        <div class="row marginClass">
          <h4 class="pull-left" id="Introduction"><small>Dados fictícios da empresa | Exemplo de Pesquisa
                            Detalhada |
                        </small></h4>
          <h6 class="dc-data-count" style="float: left;margin-left:5px;">
            <span>
                            <span class="filter-count"></span> selected out of
            <span class="total-count"></span> records |
            <a id="reset"> Reset All </a>
            </span>
          </h6>
        </div>

        <div>
            <a id="addRow"> Add Row </a>
        </div>

        <div class="col-md-6">
          <br>
          <a id="resetTable"> Reset</a>
          <table class="table" id="Vendedores">
            <thead>
              <tr>
                <th>Sales</th>
                <th>Current Year</th>
                <th>Last Year</th>
              </tr>
            </thead>
          </table>
        </div>
      </div>
    </div>
  </div>
</body>