English version

Пример построения организационной диаграммы в SharePoint 2010 / 2013 на JavaScript (часть 2)

Продолжение статьи: Пример построения организационной диаграммы в SharePoint 2010 / 2013 на JavaScript (часть 1)

Настало время разобрать пример.

Для начала определение ресурсов и библиотек.

<link rel="stylesheet" href="/_layouts/15/_cib/jOrgChart/css/jquery.jOrgChart.css"/>

<link rel="stylesheet" href="/_layouts/15/_cib/jOrgChart/css/custom.css"/>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>

<!--script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"></script-->

<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery.SPServices/2013.01/jquery.SPServices-2013.01.min.js"></script>

<script src="/_layouts/15/_cib/jOrgChart/jquery.jOrgChart.js"></script>

Стоит отметить, что jQuery и SPServices, как в прочем и jQuery UI, добавлены как ссылки на CDN. Для внутренних реализаций на забудьте поменять на локальные определения. jQuery UI так вообще закоментирован, раскоментировать его может понадобится, если потребуется дополнительный элемент интерактивности в виде drag&drop'а, но в примере без него.

Для того, чтобы с помощью jOrgChart сформировать в браузере диаграмму нужно сформировать в DOM'е конструкцию вида:

<ul id="orgDiagramDataDom">

    <li>Node 1

        <ul>

            <li>Node 1.1</li>

            <li>Node 1.2</li>

        </ul>

    </li>

</ul>

И выполнить следущую инициализацию:

$("#orgDiagramDataDom").jOrgChart({

    chartElement : '#chart'

});

Где, orgDiagramDataDom - ИД элемента UL со структурой, chart - ИД элемента div в DOM, куда мы хотим вставить сформированную диаграмму.

К слову о самой диаграмме, она вставляется не как canvas, а это структура таблиц и div'ов. Не буду судить о том на сколько это плохо или хорошо. Мы же делаем пример, для примера - это хорошо, т.к. просто. А если в структуре диаграммы не особо много элементов на одном уровне, так это вообще шикарно, т.к. пример может быстро помочь в своей реализации.

Кстати, я довольно много перебрал библиотек для визуализации организационных диаграмм на JS. Есть еще интересный вариант - Basic Primitives, в нем довольно нестандартно обыгран сценарий с большим количеством элементов на одном уровне иерархии. Даже, пожалуй, приведу скриншот:

jOrgChart был выбран для примера по 2-м причинам: у него "лучше" лицензионные политики, он проще и не перегружен функциональностью.

Вернемся к реализации примера.

В итоге нам необходимо сформировать структуру ul-li элементов на основании данных из SharePoint и инициировать jOrgChart.

Из особенностей, которые надо понимать, - головным может выступать только один элемент. На первом уровне все, кроме первого li будут игнорироваться на корню.

Перед формированием DOM'а для обработки плагином, сформируем JSON объект с похожей структурой:

var cib_OrgChartData = {

    nodeId: "r0", // Идентификатор узла

    nodeTitle: "Группа компаний", // Отображаемое наименование в блоге диаграммы

    nodeCollapse: false, // Задание узла свернутым по-умолчанию

    // Дочерние элементы

    nodeChilds: [{

            nodeId: "r1",

            nodeTitle: "Москва",

            nodeCollapse: true,

            nodeChilds: [] // Дочерние элементы вложеной структуры

        }]

};

Правильно будет с использованием jStorage проверить/взять/обновить данные из Local Storage, т.е. произвести 0 или 1 запрос к серверу за данными. В академических целях мы сделаем рекурсивную функцию, которая обращается за данными на каждом уровне узла, т.е. получает только дочерние элементы одного уровня вложенности. Такой сценарий применим в случаях большого количества данных и загрузки данных по узлу "по требованию".

var getAllChildDepts = function getAllChildDeptsF(nodeObject, ParentDeptID, DivisionName) {

    var myCAMLQuery = "<Query><Where><And>"+

                        "<Eq><FieldRef Name='Division' /><Value Type='Lookup'>"+DivisionName+"</Value></Eq>"+

                        "<Eq><FieldRef Name='ParentDept' LookupId='TRUE' /><Value Type='Count'>"+ParentDeptID+"</Value></Eq>"+

                      "</And></Where></Query>";

    var myCAMLQueryOptions = "<QueryOptions><ViewAttributes Scope='RecursiveAll' IncludeRootFolder='True' /></QueryOptions>";
    $().SPServices({

        operation: "GetListItems",

        async: false,

        listName: "Подразделения",

        CAMLViewFields: "<ViewFields><FieldRef Name='ID' /><FieldRef Name='Title' /><FieldRef Name='Division' /><FieldRef Name='ParentDept' /></ViewFields>",

        CAMLQuery: myCAMLQuery,

        CAMLQueryOptions: myCAMLQueryOptions,

        completefunc: function (xData, Status) {

        $(xData.responseXML).SPFilterNode("z:row").each(function() {

            nodeObject.nodeChilds.push({               

                nodeId: $(this).attr("ows_ID"),

                nodeTitle: $(this).attr("ows_Title"),

                nodeDivision: DivisionName,

                nodeCollapse: false,

                nodeChilds: []

            });

        });

        $.each(nodeObject.nodeChilds, function(i, dataM) {

            getAllChildDeptsF(dataM, dataM.nodeId, DivisionName);

        });

        }

    });

};

Забыл предупредить, в примере помимо подчиненности подразделений добавлен элемент статики в виде деления на дивизионы.

Функция обращается к списку с DisplayName "Подразделения", в котором должны быть атрибуты "Title", "ParentDept" - лукап на список "Подразделения", "Division" - лукап на линейный список с дивизионами.

В ответственный момент происходит вызов getAllChildDepts(dataL, dataL.nodeId, lookupValStr).

В итоге имеем объект cib_OrgChartData с полностью загруженной структурой, которую рекурсивно обрабатываем так, генерируя долгожданный DOM для диаграммы:

var orgDomBuilder = function orgDomBuilderF(OrgChartData, rootDom) {

    // Определение шаблона для узла

    rootDom.append("<li "+(OrgChartData.nodeCollapse ? "class=collapsed" : "")+" id="" + OrgChartData.nodeId + "">" + OrgChartData.nodeTitle +

                   "<div class='openNodeIcon'>" +

                           "<img src='/_layouts/15/_cib/jOrgChart/images/plusIcon.gif' />"+

                       "</div></li>");

    if (typeof OrgChartData.nodeChilds !== "undefined") {

        $.each(OrgChartData.nodeChilds, function(el, data) {

            if ($("#"+OrgChartData.nodeId).children("ul").length === 0) {

                $("#"+OrgChartData.nodeId).append("<ul></ul>");

            }

            orgDomBuilderF(data, $("#"+OrgChartData.nodeId).children("ul"));

        });

    }

};

В общем-то, все. Вызываем orgDomBuilder(cib_OrgChartData, $("#orgDiagramDataDom")) и инициируем jOrgChart, наслаждаемся.

В примере, что можно скачать ниже нужно заглянуть в cib_jOrgChartSP.html, его содержимое можно скопировать и вставить в ScriptEWP. Заработает и в 2010 и в 2013. В SharePoint 2013 при включенном Minimal Download Stratagy не забудьте про RegisterModuleInit(). Но это тема отдельной статьи.

Еще раз взгляним на то, что получилось:

В примере, помимо всего, подогнана тематика и немножко докручена CSS в части поведения при свертывании / развертывании узла, а именно, по сравнению со стандартным поведением, при свертывании и освобождении места соседние узлы "прикрепляются" друг к другу, когда по-умолчанию такого не происходит.


Опубликовано: 01.02.2014
Автор: Андрей Кольтяков