Список слоев (GeoExt и TreePanel)

Решенные задачи, первая запись - описание решения.
Ответить
Аватара пользователя
Mavka
Гуру
Сообщения: 2060
Зарегистрирован: 14 мар 2008, 17:36
Репутация: 9

Список слоев (GeoExt и TreePanel)

Сообщение Mavka » 17 авг 2011, 23:49

Чуть более сложный пример, чем в Layer Tree Tutorial. Главное отличие - список слоев берется не с карты.

Для отображения возьмем виджет Ext.tree.TreePanel. В него добавим корневой узел (root) типа GeoExt.tree.LayerContainer. Этот класс умеет загружать список слоев из GeoExt.data.LayerStore.

В нашем случае список слоев получается из запроса GetCapabilities. Создаем хранилище и загружаем его:

Код: Выделить всё

store = new GeoExt.data.LayerStore({
    url: "http://localhost/wfs?service=WFS&request=GetCapabilities",
    reader: new GeoExt.data.WFSCapabilitiesReader()
});
store.load(); 
Обратите внимание на использованный reader - он нужен для парсинга результатов. В GeoExt предусмотрен специальный WFSCapabilitiesStore, но он основан на общем классе Ext.data.Store и не содержит некоторых нужных методов для работы в связке с LayerContainer.

Создаем корневой узел дерева:

Код: Выделить всё

layerList = new GeoExt.tree.LayerContainer({
    layerStore: store,
    expanded: true
}); 
И непосредственно само дерево:

Код: Выделить всё

layerTree = new Ext.tree.TreePanel({
    renderTo: 'tree-div',
    root: layerList,
    rootVisible: false
}); 
Так как метод store.load() работает асинхронно, то на момент создания layerList хранилище будет пустым и, соответственно, узел не получит дочерних элементов. (Можно отложить инициализацию установив 'expanded: false' и 'rootVisible: true', тогда загрузка дочерних элементов произойдет при ручном раскрытии узла.) Добавим в LayerStore обработчик события 'load':

Код: Выделить всё

store = new GeoExt.data.LayerStore({
    ...
    listeners: {
        load: function() {
            layerList.reload();
        }
    }
}); 
Все, дерево слоев готово. Теперь попробуем контролировать процесс создания дочерних элементов. Допустим, нам требуется убрать из дерева некоторые слои, а для остальных изменить английское имя на русское (взяв его из abstract в getCapabilities).

Добавим в LayerContainer загрузчик:

Код: Выделить всё

var myloader = new GeoExt.tree.LayerLoader({
    store: store,
    filter: function(record) {
        if (record.data.name == 'lakes') {
            return false;
        } else {
            return true;
        }
    },
    createNode: function (attr) {
        attr.layer.name =
            this.store.getById(attr.layer.id).get('abstract')
        // стандартная функция создания узла
        return GeoExt.tree.LayerLoader.prototype.createNode.call(this, attr);
    }
});

layerList = new GeoExt.tree.LayerContainer({
    ...
    loader: myloader
}); 
Использованы две функции:
  • filter - используется для отбраковки ненужных узлов (эти слои не будут показаны в дереве), возвращает true/false;
  • createNode - функция создания узла.
лангольеры под окном жрали время ом-ном-ном

Аватара пользователя
Denis Rykov
Гуру
Сообщения: 3376
Зарегистрирован: 11 апр 2008, 21:09
Репутация: 529
Ваше звание: Author
Контактная информация:

Re: Список слоев (GeoExt и TreePanel)

Сообщение Denis Rykov » 18 авг 2011, 04:39

Отличный рецепт! Небольшое дополнение: в последнем случае при использовании LayerContainer с загрузчиком layerList будет выглядеть так:

Код: Выделить всё

layerList = new GeoExt.tree.LayerContainer({
    expanded: true,
    loader: myloader
}); 
То есть следующую строку мы убрали:

Код: Выделить всё

layerStore: store
Spatial is now, more than ever, just another column- The Geometry Column.

Аватара пользователя
Mavka
Гуру
Сообщения: 2060
Зарегистрирован: 14 мар 2008, 17:36
Репутация: 9

Re: Список слоев (GeoExt и TreePanel)

Сообщение Mavka » 18 авг 2011, 09:15

Да. То что в документации пишут про "this property will be set as the store option of the loader" работает только при таком хитром объявлении загрузчика:

Код: Выделить всё

layerList = new GeoExt.tree.LayerContainer({
    layerStore: store,
    expanded: true,
    loader: {
        createNode: function (attr) {
            attr.layer.name = this.store.getById(attr.layer.id).get('abstract')
            return GeoExt.tree.LayerLoader.prototype.createNode.call(this, attr);
        }
    }
}); 
Т.е. loader указан как набор свойств даже без указания класса.

P.S. И, да, я ошибался. Автоматическая синхронизация дерева с хранилищем как в таблицах не работает. Почему разработчики не предусмотрели прозрачную состыковку события 'load' и reload для узла? Может быть посчитали, что на практике деревья имеют сложную структуру и не стоит ее ломать при обновлении...
лангольеры под окном жрали время ом-ном-ном

Аватара пользователя
Mavka
Гуру
Сообщения: 2060
Зарегистрирован: 14 мар 2008, 17:36
Репутация: 9

Re: Список слоев (GeoExt и TreePanel)

Сообщение Mavka » 29 авг 2011, 14:28

Вариант без LayerContainer при ручном добавлении слоев в дерево:
http://pastie.org/2447996
лангольеры под окном жрали время ом-ном-ном

Аватара пользователя
Mavka
Гуру
Сообщения: 2060
Зарегистрирован: 14 мар 2008, 17:36
Репутация: 9

Re: Список слоев (GeoExt и TreePanel)

Сообщение Mavka » 30 авг 2011, 12:02

Нода для дерева с кастомным стилем (myfolder):

Код: Выделить всё

layerTree.root.appendChild([
    new Ext.tree.TreeNode({text: 'mynode', cls: 'myfolder'}),
]); 
Стили CSS:

Код: Выделить всё

.myfolder.x-tree-node-leaf .x-tree-node-icon {        // простой узел
    background-image: url("images/default/grid/hmenu-lock.png");
}
.myfolder.x-tree-node-collapsed .x-tree-node-icon {   // закрытая папка
    background-image: url("images/default/grid/hmenu-lock.png");
}
.myfolder.x-tree-node-expanded .x-tree-node-icon {    // открытая папка
    background-image: url("images/default/grid/hmenu-unlock.png");
} 
Или без префикса ".myfolder" если хотите перебить стили глобально

P.S. В случае если дочки добавляются асинхронно, то нода первоначально имеет вид листка. Что бы сразу придать ей вид папки, добавьте в описание (для стандартного стиля):

Код: Выделить всё

cls: "x-tree-node-collapsed" 
Она сразу будет выглядеть как "закрытая папка", а когда добавите дочерние узлы, то начнет работать как обычно - "закрытая/открытая папка".
Последний раз редактировалось Mavka 06 ноя 2011, 22:59, всего редактировалось 1 раз.
лангольеры под окном жрали время ом-ном-ном

Аватара пользователя
Mavka
Гуру
Сообщения: 2060
Зарегистрирован: 14 мар 2008, 17:36
Репутация: 9

Re: Список слоев (GeoExt и TreePanel)

Сообщение Mavka » 12 сен 2011, 14:11

Загрузка в дерево конфигурации вида:

Код: Выделить всё

[
{"text": "Виды", "layer": "Виды", "leaf": true, "checked": true, "children": []},
{"text": "Усадьбы","layer": "Усадьбы", "leaf": true, "checked": true, "children": []}
]

Создаем новую ноду, в children передаем json-конфиг и в дерево ставим новый root:

Код: Выделить всё

function loadJSON() {
Ext.Ajax.request({
url: 'config.js',
method: 'GET',
success: function(response, request) {
var result = Ext.decode(response.responseText);
var root = new Ext.tree.AsyncTreeNode({
text: 'root',
children: result,
expanded: true
});
layerTree.setRootNode(root);
}
});
}

Так подойдет? Или нужно через TreeLoader?
лангольеры под окном жрали время ом-ном-ном

Аватара пользователя
Denis Rykov
Гуру
Сообщения: 3376
Зарегистрирован: 11 апр 2008, 21:09
Репутация: 529
Ваше звание: Author
Контактная информация:

Re: Список слоев (GeoExt и TreePanel)

Сообщение Denis Rykov » 12 сен 2011, 21:29

Да, спасибо!
А как поступить, если в json-е хранятся не дети, а полностью рутовая нода?

Ответ: result[0].children
Spatial is now, more than ever, just another column- The Geometry Column.

Ответить

Вернуться в «Рецепты»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 5 гостей