У меня есть данные, в которых есть глубины, и мне нужно отобразить эти данные, отображающие глубину вложенности. Как только данные визуализируются, их нужно сортировать так, чтобы каждая «глубина» сортировалась независимо, но оставалась прикрепленной к ней.Сортировка дерева Javascript
До сих пор мне удалось преобразовать глубины в дерево, как массив объектов, и на основе этого сделать рендер. У меня есть сортировка на месте, но я не могу понять, как заставить дочерние элементы оставаться относительно родителя.
Вот код, который я написал до сих пор:
var data = getData();
// convert the data to a tree structure
var tree = convertToTree(data);
$(function($) {
init();
function init() {
renderTree(tree);
}
function renderTree(tree) {
var $table = $('#tree1');
var rows = [];
function renderTreeRow(row) {
if (row.hasOwnProperty('score')) {
rows.push([
'<tr class="depth_' + row.depth + '">',
' <td>' + row.label + '</td>',
' <td>' + row.row + '</td>',
' <td>' + row.depth + '</td>',
' <td>' + row.score + '</td>',
' <td>' + row.count + '</td>',
'</tr>'
]);
} else {
rows.push([
'<tr class="depth_' + row.depth + ' group_heading">',
' <td colspan="5">' + row.label + '</td>',
'</tr>'
]);
}
if (row.hasOwnProperty('children') && row.children.length) {
$.each(row.children, function(i, childRow) {
renderTreeRow(childRow);
});
}
}
$.each(tree, function(i, row) {
renderTreeRow(row);
});
$table.find('tbody tr').remove();
$('tbody', $table).append(rows.join(''));
}
$('th[data-sort-asc]').off('.data_sort_asc').on('click.data_sort_asc', function(event) {
var target = $(event.target).closest('th');
var sortAscending = target.attr('data-sort-asc') == "true";
var property = target.attr('data-sort-property');
var treeSorter = sortByProperty(property, sortAscending);
treeSorter(tree);
renderTree(tree);
// flip sort direction
target.attr('data-sort-asc', !sortAscending);
target.find('span').remove().end().append('<span class="glyphicon glyphicon-sort-by-attributes' + (sortAscending ? '' : '-alt') + '" aria-hidden="true"></span>');
}).append('<span class="glyphicon glyphicon-sort" aria-hidden="true"></span>')
.css({
'cursor': 'pointer'
});
});
function sortByProperty(property, ascending) {
ascending = ascending !== undefined ? ascending : true;
var flip = ascending ? 1 : -1;
function sortTree(arr) {
function compare(a, b) {
if (a[property] < b[property]) {
return -1 * flip;
}
if (a[property] > b[property]) {
return 1 * flip;
}
return 0;
}
$.each(arr, function(i, el) {
if (el.hasOwnProperty('children')) {
sortTree(el.children);
}
});
arr.sort(compare);
}
return sortTree;
}
/*
function flatternTree(tree) {
\t var ret = [];
\t $.each(tree, function(i, row) {
\t \t ret.push(row);
\t \t if(row.hasOwnProperty('children') && row.children.length) {
\t \t \t ret = ret.concat(flatternTree(row.children));
\t \t }
\t });
\t return ret;
}
*/
function convertToTree(arr) {
return treeify(splitToSegments(arr));
}
function splitToSegments(arr) {
var result = [];
var accum, segment;
$.each(arr, function(i, it) {
if (it.depth === 0) {
accum = true;
if (segment && segment.length) {
result.push(segment);
}
segment = [it];
} else if (accum) {
segment.push(it);
}
});
if (segment && segment.length) {
result.push(segment);
}
return result;
}
function treeify(arr) {
return arr.map(function(o) {
return o.reduce(function(a, b) {
var lastChild;
a.children = a.children || [];
if (a.depth + 1 === b.depth) {
a.children.push(b);
} else {
lastChild = a.children[a.children.length - 1];
lastChild.children = lastChild.children || [];
lastChild.children.push(b);
}
return a;
});
});
}
function getData() {
// rows of data that we get, we have depth but not nested as parent>child relationships. The order & depth determines parent>child relationship
var payload = [
{row: 1, group: "group_30", "depth": 0, "label": "TOP"},
{row: 2, group: "group_30", "depth": 1, "score": 10, "count": 600, "label": "A1"},
{row: 3, group: "group_30", "depth": 2, "score": 10, "count": 100, "label": "A1>2-1"},
{row: 4, group: "group_30", "depth": 3, "score": 222, "count": 9, "label": "A1>2-1>3-1"},
{row: 5, group: "group_30", "depth": 3, "score": 22, "count": 99, "label": "A1>2-1>3-2"},
{row: 6, group: "group_30", "depth": 2, "score": 20, "count": 200, "label": "A1>2-2"},
{row: 7, group: "group_30", "depth": 3, "score": 222, "count": 9, "label": "A1>2-2>3-1"},
{row: 8, group: "group_30", "depth": 3, "score": 22, "count": 99, "label": "A1>2-2>3-2"},
{row: 9, group: "group_30", "depth": 2, "score": 30, "count": 300, "label": "A1>2-3"},
{row: 10, group: "group_30", "depth": 3, "score": 222, "count": 9, "label": "A1>2-3>3-1"},
{row: 11, group: "group_30", "depth": 3, "score": 22, "count": 99, "label": "A1>2-3>3-2"},
{row: 12, group: "group_30", "depth": 1, "score": 10000, "count": 10, "label": "B1"},
{row: 13, group: "group_30", "depth": 2, "score": 1000, "count": 1, "label": "B1>2-1"},
{row: 14, group: "group_30", "depth": 3, "score": 222, "count": 9, "label": "B1>2-1>3-1"},
{row: 15, group: "group_30", "depth": 3, "score": 22, "count": 99, "label": "B1>2-1>3-2"},
{row: 16, group: "group_30", "depth": 2, "score": 3000, "count": 3, "label": "B1>2-2"},
{row: 17, group: "group_30", "depth": 3, "score": 222, "count": 9, "label": "B1>2-2>3-1"},
{row: 18, group: "group_30", "depth": 3, "score": 22, "count": 99, "label": "B1>2-2>3-2"},
{row: 19, group: "group_30", "depth": 2, "score": 6000, "count": 6, "label": "B1>2-3"},
{row: 20, group: "group_30", "depth": 3, "score": 222, "count": 9, "label": "B1>2-3>3-1"},
{row: 21, group: "group_30", "depth": 3, "score": 22, "count": 99, "label": "B1>2-3>3-2"}
];
return payload;
}
/* Styles go here */
.depth_0 {
background-color: #B2A788;
}
.depth_1 {
background-color: #7686B2;
}
.depth_2 {
background-color: #9BC2CC;
}
.depth_3 {
background-color: #DCE5FF;
}
.group_heading td {
border-bottom: 3px solid #BFB8A5
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p>Clicking the headers should sort each 'grouping' independantly, so that child elements appear directly after the parent. When the parent is sorted the child elements should move with it. Thanks!</p>
<table id="tree1" class="table">
<thead>
<tr>
<th>label</th>
<th data-sort-asc="true" data-sort-property="row">row</th>
<th data-sort-asc="true" data-sort-property="depth">depth</th>
<th data-sort-asc="true" data-sort-property="score">score</th>
<th data-sort-asc="true" data-sort-property="count">count</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
Спасибо за любые мысли!