Это очень нестандартный графический интерфейс, поэтому я бы использовал довольно домашнее решение. Я бы разбил проблему на несколько шагов и возложил бы на браузер ответственность за большую часть работы (например, JavaScript).
Сначала вы хотите, чтобы объект представлял данные. Исходя из этой проблемы, я хотел бы предложить вам трехуровневую структуру объекта: одну для представления пользователя (каждая строка в примере); дочерний массив в этом объекте будет содержать данные каждого дня; и каждый член массива будет объектом, который содержит ячейки, выбранные пользователем. JSP будет отвечать за написание этой структуры данных, но JavaScript возьмет ее оттуда. Вот как будут выглядеть конструкторы:
function DayOfData(dateString, dataObject) {
this.date = Date.parse(dateString); //storing a Date is cleaner separation of presentation & data
this.dataCells = dataObject;
}
function User(name, email, role) {
this.name = name; //and so on
this.data = [];
this.addData = function(date, dataSet) {
this.data.push( new DayOfData(date, dataObject) );
}
}
Инстанции, написанные JSP (или что-то среднее), будут выглядеть так:
var users = []; //a global to hold it all
users[someId] = new User("foo", "foo@something.org", "boss");
users[someId].addData("1/1/1970", {"label 1": 23, "label 2": "test"} );
//...and so on
Обратите внимание на объект JSON, в котором хранятся ячейки данных, выбранные пользователем для отображения. В этом анонимном объекте я сопоставляю визуальную метку со значением; это проще, чем создавать еще один дочерний объект, чтобы абстрагировать метку от некоторого уникального идентификатора. Вы могли бы сделать этот дополнительный шаг, если бы это было действительно необходимо, но это еще один уровень в иерархии, поэтому я думаю, что лучше пойти по более простому пути.
(Конечно, вы хотели бы правильно распределить пространство имен ... Я использую голые глобальные переменные для упрощения синтаксиса. Для действительно надежной системы я бы также использовал закрытые члены.)
Я бы использовал TrimPath на этапе отображения (после того, как JSP выписал данные в этой структуре). Просто передайте массив users в шаблон, который будет выглядеть примерно так (он будет помещен в таблицу с помощью кода отображения после его обработки TrimPath):
<tbody>
{for user in user}
<tr>
<td>${user.name}</td> <!-- and so on -->
{for day in user.data}
{for datum in day}
<td>${datum}</td>
{/for}
{/for}
</tr>
{for}
</tbody>
Для написания строки заголовка вам потребуется внести небольшие изменения в этот шаблон, хотя вы, вероятно, могли бы сделать это проще в коде на стороне сервера, поскольку он не является динамической частью графического интерфейса. Чтобы строка метки «зависла» в верхней части таблицы (это будет элемент THEAD), просто используйте CSS, чтобы установить высоту TBODY, а затем установите для overflow-y значение «scroll». Это должно достичь желаемого эффекта.
Чтобы выполнить повторную сортировку столбцов, вы фактически должны повторно отсортировать массив пользователей (см. Описания Array.sort ) в зависимости от столбца, по которому пользователь щелкает. Затем очистите TBODY и повторно обработайте шаблон с помощью TrimPath .
Звучит сложно и запутанно, но на самом деле это не так. Вы хотите избежать затруднений при изменении макета, поэтому разделение данных и представления является ключевым. Коллекция объектов JavaScript только для данных в сочетании с шаблонами TrimPath (или аналогичными), как описано выше, позволяет получить хороший шаблон MVC и упростить задачу, разбив ее на отдельные этапы. Управление сортируемой таблицей данных (не говоря уже о данных, которые сгруппированы по горизонтали в основные подразделения) - это было бы почти невозможно без хорошего MVC.