How to remove empty rows in tables when they are zero, and how to allow selection in only one table at a time?

笑着哭i 提交于 2020-02-05 14:55:16

问题


I created two tables that relate. When I select one or more items from Table A, Table B is resized according to that selection and vice versa.

However, I need to lock the selection of the two tables at the same time. For example, if I click on the sellers Miguel andSede, in Table B the values and cities corresponding to these two sellers will be rendered. And if in Table B I click on the cities of Faro andLoulé, automatically the sellers Miguel andSede should be deselected.

What happens at the moment is that I can make selections in both tables at the same time, as shown in the image below:

I need to create a rule where if I have a selection in Table A and click on Table B. The line selected in Table A has no background color and vice versa.

When I make a selection, some lines are empty, but they still appear, as shown in the image below:

How can I prevent these lines from appearing if there is no selection?

I apologize for asking two questions at the same time, as it is the same code I have found better to use here.

Here's my code, thanks in advance.

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

var url = 'https://gist.githubusercontent.com/bernalvinicius/3cece295bc37de1697e7f83418e7fcc9/raw/a5820379ec6eae76ee792495cc5dd1685c977a73/vendedores.json';
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);

    citiesDim = myCrossfilter.dimension(function(d) {
      return d.zona;
    });
    var citiesGroup = citiesDim.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,
      };
    }

    //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)

    //CityTable
    citiesTable.width(500)
      .height(480)
      .dimension(citiesGroup)
      .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);
    });

    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]);
          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);
    citiesTable.filter(null);
    citiesDim.filter(null);

    dc.redrawAll();
  });

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

    dc.redrawAll();
  });

  $('#resetTable2').on('click', function() {
    vendedorTable.filter(null);
    vendedorDim.filter(null);
    citiesTable.filter(null);
    citiesDim.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-10" 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> selecionado dentre
            <span class="total-count"></span> registros |
            <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 class="col-md-6">
          <br>
          <a id="resetTable2"> Reset</a>
          <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>

回答1:


I'm not sure that I understand the first question.

As for the second question, currently you are filtering out the data inside of the formatting functions for the table:

  .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
        }) + '€';
      }
    }
  ])

That works, but it's a weird way to go about it for two reasons:

  1. while(...) means "repeat until false". if(...) would be more idiomatic here.
  2. More importantly, this still prints the rows, but if the values are zero or NaN, it prints undefined (the default return value for a function in JavaScript) and this shows up as an empty cell.

It would be better to filter the data before it gets to the table. You can do this using a fake group. Specifically, you can create an object which supports the .top(N) function that the table will use to pull data, but skips any rows where either of these values is close to zero:

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; // does it have a value?
            }).slice(0, N);
        }
    };
}

Apply this function to each of your groups:

    vendedorTable.width(500)
      .height(480)
      .dimension(remove_empty_bins(vendedorGroup))

    citiesTable.width(500)
      .height(480)
      .dimension(remove_empty_bins(citiesGroup))

And now your formatting functions can stick to formatting!

      .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
            }) + '€';
        }
      ])

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; // does it have a value?
        }).slice(0, N);
    }
};
}
var url = 'https://gist.githubusercontent.com/bernalvinicius/3cece295bc37de1697e7f83418e7fcc9/raw/a5820379ec6eae76ee792495cc5dd1685c977a73/vendedores.json';
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);

    citiesDim = myCrossfilter.dimension(function(d) {
      return d.zona;
    });
    var citiesGroup = citiesDim.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,
      };
    }

    //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(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)

    //CityTable
    citiesTable.width(500)
      .height(480)
      .dimension(remove_empty_bins(citiesGroup))
      .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);
    });

    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]);
          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);
    citiesTable.filter(null);
    citiesDim.filter(null);

    dc.redrawAll();
  });

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

    dc.redrawAll();
  });

  $('#resetTable2').on('click', function() {
    vendedorTable.filter(null);
    vendedorDim.filter(null);
    citiesTable.filter(null);
    citiesDim.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-10" 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> selecionado dentre
            <span class="total-count"></span> registros |
            <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 class="col-md-6">
          <br>
          <a id="resetTable2"> Reset</a>
          <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>


来源:https://stackoverflow.com/questions/59955008/how-to-remove-empty-rows-in-tables-when-they-are-zero-and-how-to-allow-selectio

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!