如何使用 d3.js 按不同的变量对 table 进行排序?
How can I use d3.js to sort a table by different variables?
data = [
{
"name": "Dave",
"dept": "Marketing",
"region": "South",
"items": 28
},
{
"name": "Amy",
"dept": "IT",
"region": "West",
"items": 46
},
{
"name": "John",
"dept": "Sales",
"region": "North",
"items": 35
},
{
"name": "Sarah",
"dept": "Communications",
"region": "North",
"items": 13
}
]
drawTable(data)
sortTable(data)
function drawTable(data) {
// not working
// when redrawing table, trying to re-initialize sort function
sortTable(data)
d3.select('#data-table').remove()
let table = d3.select('#table').append('div').attr('id', 'data-table')
let row = table.selectAll('.row')
.data(data)
.enter()
.append('div')
.attr('class', 'row')
let grid = row
.append('div')
.attr('class', 'grid')
let name = grid.append('div')
.attr('class', 'box')
.html(d => d.name)
let dept = grid.append('div')
.attr('class', 'box')
.html(d => d.dept)
let region = grid.append('div')
.attr('class', 'box')
.html(d => d.region)
let items = grid.append('div')
.attr('class', 'box')
.html(d => d.items)
}
function sortTable(data) {
d3.selectAll(".name,.dept,.region,.items").on('click', function () {
let sortWhich = d3.select(this).attr("class")
console.log('sortWhich', sortWhich)
let tableSort
if (sortWhich == "name") {
tableSort = data.sort((a, b) => d3.ascending(a.name, b.name))
} else if (sortWhich == "dept") {
tableSort = data.sort((a, b) => d3.ascending(a.dept, b.dept))
} else if (sortWhich == 'region') {
tableSort = data.sort((a, b) => d3.ascending(a.region, b.region))
} else {
tableSort = data.sort((a, b) => d3.ascending(a.items, b.items))
}
// Can I combine the above and pass a variable to a sort function? This is not working:
// let tableSort = data.sort((a, b) => a.sortWhich - b.sortWhich)
drawTable(tableSort)
})
}
html,
body {
height: 100%;
margin: 0;
}
.grid {
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.grid>div {
display: flex;
flex-basis: calc(100%/4 - 28px);
justify-content: center;
flex-direction: column;
padding: 10px;
}
.box {
margin: 0;
}
.box {
color: #000;
border: .5px solid #ccc;
}
.hrbox {
background-color: #333;
color: #fff;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v6.min.js"></script>
</head>
<body>
<div id="table">
<div class="grid">
<div class="box hrbox name">
<div>name</div>
</div>
<div class="box hrbox dept">
<div>dept</div>
</div>
<div class="box hrbox region">
<div>region</div>
</div>
<div class="box hrbox items">
<div>items</div>
</div>
</div>
<div id="data-table"></div>
</div>
</body>
我使用 d3.js 创建了一个 flexbox table,它提取 json 数据来填充它。
我希望能够按 header 行对每一列进行排序,为此我编写了一个排序函数。但是,我现在一次只能对一列进行排序。然后,如果我刷新页面,我可以对不同的列进行排序。我希望能够在不需要刷新页面的情况下进行切换。所以 - 按名称排序,然后决定按项目排序,然后按区域排序,以查看数据的不同视图。我错过了什么?
如果有任何反馈,我将不胜感激。
[我还想要一个排序函数,我将一个变量传递给它,而不是拥有所有这些条件。我不确定这是否可能。 (绝对不是我主要关心的问题。)但是把它放在那里]
谢谢!
如果您查看控制台,您会发现 sortWhich
始终类似于 "box hrbox whatever"
,因此所有条件都将失败,代码将转到 else
在底部。
最简单的解决方案是使用 includes()
:
if (sortWhich.includes("name")) etc...
这是您的代码,其中包含该更改:
data = [{
"name": "Dave",
"dept": "Marketing",
"region": "South",
"items": 28
},
{
"name": "Amy",
"dept": "IT",
"region": "West",
"items": 46
},
{
"name": "John",
"dept": "Sales",
"region": "North",
"items": 35
},
{
"name": "Sarah",
"dept": "Communications",
"region": "North",
"items": 13
}
]
drawTable(data)
sortTable(data)
function drawTable(data) {
// not working
// when redrawing table, trying to re-initialize sort function
sortTable(data)
d3.select('#data-table').remove()
let table = d3.select('#table').append('div').attr('id', 'data-table')
let row = table.selectAll('.row')
.data(data)
.enter()
.append('div')
.attr('class', 'row')
let grid = row
.append('div')
.attr('class', 'grid')
let name = grid.append('div')
.attr('class', 'box')
.html(d => d.name)
let dept = grid.append('div')
.attr('class', 'box')
.html(d => d.dept)
let region = grid.append('div')
.attr('class', 'box')
.html(d => d.region)
let items = grid.append('div')
.attr('class', 'box')
.html(d => d.items)
}
function sortTable(data) {
d3.selectAll(".name,.dept,.region,.items").on('click', function() {
let sortWhich = d3.select(this).attr("class")
console.log('sortWhich', sortWhich)
let tableSort
if (sortWhich.includes("name")) {
tableSort = data.sort((a, b) => d3.ascending(a.name, b.name))
} else if (sortWhich.includes("dept")) {
tableSort = data.sort((a, b) => d3.ascending(a.dept, b.dept))
} else if (sortWhich.includes('region')) {
tableSort = data.sort((a, b) => d3.ascending(a.region, b.region))
} else {
tableSort = data.sort((a, b) => d3.ascending(a.items, b.items))
}
// Can I combine the above and pass a variable to a sort function? This is not working:
// let tableSort = data.sort((a, b) => a.sortWhich - b.sortWhich)
drawTable(tableSort)
})
}
html,
body {
height: 100%;
margin: 0;
}
.grid {
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.grid>div {
display: flex;
flex-basis: calc(100%/4 - 28px);
justify-content: center;
flex-direction: column;
padding: 10px;
}
.box {
margin: 0;
}
.box {
color: #000;
border: .5px solid #ccc;
}
.hrbox {
background-color: #333;
color: #fff;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v6.min.js"></script>
</head>
<body>
<div id="table">
<div class="grid">
<div class="box hrbox name">
<div>name</div>
</div>
<div class="box hrbox dept">
<div>dept</div>
</div>
<div class="box hrbox region">
<div>region</div>
</div>
<div class="box hrbox items">
<div>items</div>
</div>
</div>
<div id="data-table"></div>
</div>
</body>
这里有一些问题:
sort()
就地排序数组,不需要 tableSort
变量
- 再次删除绘制 table 的元素是 不是 惯用的 D3,只需使用 enter/update/exit 选择。
关于你的第二个问题,如果你有正确的变量名,你可以只使用括号表示法,删除所有 if...else
部分:
data.sort((a, b) => d3.ascending(a[sortWhich], b[sortWhich]))
data = [
{
"name": "Dave",
"dept": "Marketing",
"region": "South",
"items": 28
},
{
"name": "Amy",
"dept": "IT",
"region": "West",
"items": 46
},
{
"name": "John",
"dept": "Sales",
"region": "North",
"items": 35
},
{
"name": "Sarah",
"dept": "Communications",
"region": "North",
"items": 13
}
]
drawTable(data)
sortTable(data)
function drawTable(data) {
// not working
// when redrawing table, trying to re-initialize sort function
sortTable(data)
d3.select('#data-table').remove()
let table = d3.select('#table').append('div').attr('id', 'data-table')
let row = table.selectAll('.row')
.data(data)
.enter()
.append('div')
.attr('class', 'row')
let grid = row
.append('div')
.attr('class', 'grid')
let name = grid.append('div')
.attr('class', 'box')
.html(d => d.name)
let dept = grid.append('div')
.attr('class', 'box')
.html(d => d.dept)
let region = grid.append('div')
.attr('class', 'box')
.html(d => d.region)
let items = grid.append('div')
.attr('class', 'box')
.html(d => d.items)
}
function sortTable(data) {
d3.selectAll(".name,.dept,.region,.items").on('click', function () {
let sortWhich = d3.select(this).attr("class")
console.log('sortWhich', sortWhich)
let tableSort
if (sortWhich == "name") {
tableSort = data.sort((a, b) => d3.ascending(a.name, b.name))
} else if (sortWhich == "dept") {
tableSort = data.sort((a, b) => d3.ascending(a.dept, b.dept))
} else if (sortWhich == 'region') {
tableSort = data.sort((a, b) => d3.ascending(a.region, b.region))
} else {
tableSort = data.sort((a, b) => d3.ascending(a.items, b.items))
}
// Can I combine the above and pass a variable to a sort function? This is not working:
// let tableSort = data.sort((a, b) => a.sortWhich - b.sortWhich)
drawTable(tableSort)
})
}
html,
body {
height: 100%;
margin: 0;
}
.grid {
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.grid>div {
display: flex;
flex-basis: calc(100%/4 - 28px);
justify-content: center;
flex-direction: column;
padding: 10px;
}
.box {
margin: 0;
}
.box {
color: #000;
border: .5px solid #ccc;
}
.hrbox {
background-color: #333;
color: #fff;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v6.min.js"></script>
</head>
<body>
<div id="table">
<div class="grid">
<div class="box hrbox name">
<div>name</div>
</div>
<div class="box hrbox dept">
<div>dept</div>
</div>
<div class="box hrbox region">
<div>region</div>
</div>
<div class="box hrbox items">
<div>items</div>
</div>
</div>
<div id="data-table"></div>
</div>
</body>
我使用 d3.js 创建了一个 flexbox table,它提取 json 数据来填充它。 我希望能够按 header 行对每一列进行排序,为此我编写了一个排序函数。但是,我现在一次只能对一列进行排序。然后,如果我刷新页面,我可以对不同的列进行排序。我希望能够在不需要刷新页面的情况下进行切换。所以 - 按名称排序,然后决定按项目排序,然后按区域排序,以查看数据的不同视图。我错过了什么?
如果有任何反馈,我将不胜感激。
[我还想要一个排序函数,我将一个变量传递给它,而不是拥有所有这些条件。我不确定这是否可能。 (绝对不是我主要关心的问题。)但是把它放在那里]
谢谢!
如果您查看控制台,您会发现 sortWhich
始终类似于 "box hrbox whatever"
,因此所有条件都将失败,代码将转到 else
在底部。
最简单的解决方案是使用 includes()
:
if (sortWhich.includes("name")) etc...
这是您的代码,其中包含该更改:
data = [{
"name": "Dave",
"dept": "Marketing",
"region": "South",
"items": 28
},
{
"name": "Amy",
"dept": "IT",
"region": "West",
"items": 46
},
{
"name": "John",
"dept": "Sales",
"region": "North",
"items": 35
},
{
"name": "Sarah",
"dept": "Communications",
"region": "North",
"items": 13
}
]
drawTable(data)
sortTable(data)
function drawTable(data) {
// not working
// when redrawing table, trying to re-initialize sort function
sortTable(data)
d3.select('#data-table').remove()
let table = d3.select('#table').append('div').attr('id', 'data-table')
let row = table.selectAll('.row')
.data(data)
.enter()
.append('div')
.attr('class', 'row')
let grid = row
.append('div')
.attr('class', 'grid')
let name = grid.append('div')
.attr('class', 'box')
.html(d => d.name)
let dept = grid.append('div')
.attr('class', 'box')
.html(d => d.dept)
let region = grid.append('div')
.attr('class', 'box')
.html(d => d.region)
let items = grid.append('div')
.attr('class', 'box')
.html(d => d.items)
}
function sortTable(data) {
d3.selectAll(".name,.dept,.region,.items").on('click', function() {
let sortWhich = d3.select(this).attr("class")
console.log('sortWhich', sortWhich)
let tableSort
if (sortWhich.includes("name")) {
tableSort = data.sort((a, b) => d3.ascending(a.name, b.name))
} else if (sortWhich.includes("dept")) {
tableSort = data.sort((a, b) => d3.ascending(a.dept, b.dept))
} else if (sortWhich.includes('region')) {
tableSort = data.sort((a, b) => d3.ascending(a.region, b.region))
} else {
tableSort = data.sort((a, b) => d3.ascending(a.items, b.items))
}
// Can I combine the above and pass a variable to a sort function? This is not working:
// let tableSort = data.sort((a, b) => a.sortWhich - b.sortWhich)
drawTable(tableSort)
})
}
html,
body {
height: 100%;
margin: 0;
}
.grid {
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.grid>div {
display: flex;
flex-basis: calc(100%/4 - 28px);
justify-content: center;
flex-direction: column;
padding: 10px;
}
.box {
margin: 0;
}
.box {
color: #000;
border: .5px solid #ccc;
}
.hrbox {
background-color: #333;
color: #fff;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v6.min.js"></script>
</head>
<body>
<div id="table">
<div class="grid">
<div class="box hrbox name">
<div>name</div>
</div>
<div class="box hrbox dept">
<div>dept</div>
</div>
<div class="box hrbox region">
<div>region</div>
</div>
<div class="box hrbox items">
<div>items</div>
</div>
</div>
<div id="data-table"></div>
</div>
</body>
这里有一些问题:
sort()
就地排序数组,不需要tableSort
变量- 再次删除绘制 table 的元素是 不是 惯用的 D3,只需使用 enter/update/exit 选择。
关于你的第二个问题,如果你有正确的变量名,你可以只使用括号表示法,删除所有 if...else
部分:
data.sort((a, b) => d3.ascending(a[sortWhich], b[sortWhich]))