Пример построения организационной диаграммы в 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
Автор: Андрей Кольтяков