Программное создание графических схем

19.07.16

Разработка - Работа с интерфейсом

Пример динамического создания графических схем, добавления элементов любых видов. Любые схемы без бизнес-процессов. Программная работа со схемой.

Сначала я собирался накатать большую и умную статью по итогам исследования внутреннего формата различных общих объектов 1С - всяких там географических карт, дендрограмм и прочих мокселей. О том, как оно устроено, что означает тот или иной кусок и какая польза может от того получиться. Ряд манипуляций возможен только с сериализованным текстом, ряд действий просто быстрее и удобнее. Так вот, а потом мне здраво указали, что теория нафиг не нужна и вообще подавай конкретные примеры.

Сразу оговорюсь: приоритет этой идеи принадлежит безвестным гениям доледникового периода, а я, позорно протормозив, просто сделал для себя то, о чём писал Diversus ещё в лохматые годы. Но, поскольку сие может служить иллюстрацией, и к тому же более-менее работоспособно, то выкладываю в виде кода некоторые наработки как пример. Пример сериализации графической схемы в текст, работы с текстом, и последующей обратной серализации. Причём сделано это всё примитивно и топорно, безо всяких DOM.

К недостаткам схемы стоит отнести сложность позиционирования (вам самостоятельно придётся прикидывать, куда "сунуть" каждый новый объект), и капризная чувствительность к правке. Перетаскивать добавленные объекты, связанные добавленными стрелочками, не советую - всё рискует разъехаться. Но для "только просмотр" это сгодится более чем. Также, напомню, графическая схема поддерживает событие расшифровки, что делает её не просто иллюстративным инструментом, но и навигационным.

Где это может пригодиться? Начиная от построения простейших отчётов-связок, вроде "Структуры подчинённости", и заканчивая отражением связей метаданных, как это делали в механизмах, изучающих внутреннюю структуру конфигураций. Для цели отрисовки графов может пригодиться; правда, опять же, позиционирование надо продумывать самим, в отличие от стороннего софта, обычно используемого в таких случаях.

Собственно, код и все пояснения по формату в описаниях функций. Особенно см. подробное описание функции ДобавитьФигуру.

#Область РаботаСГрафическимиСхемами

&НаСервереБезКонтекста
Функция СериализоватьГС(рГС)
    зап=Новый ЗаписьXML;
    зап.УстановитьСтроку("UTF-8");
    //СериализаторXDTO.ЗаписатьXML(зап,ГС,НазначениеТипаXML.Явное,ФормаXML.Атрибут);
    СериализаторXDTO.ЗаписатьXML(зап,рГС);
    Возврат зап.Закрыть();
КонецФункции

&НаСервереБезКонтекста
Функция ДесериализоватьГС(рСтрока)
    чтен=Новый ЧтениеXML;
    чтен.УстановитьСтроку(рСтрока);
    Возврат СериализаторXDTO.ПрочитатьXML(чтен,Тип("ГрафическаяСхема"));
КонецФункции

// Преобразует значение системного перечисления в его англоязычный вариант представления
&НаКлиенте
Функция АнглИмя(рЗначение)
    Возврат СокрЛП(СериализаторXDTO.XMLСтрока(рЗначение));
КонецФункции

&НаКлиенте
// Возвращает список значений, где значение - тип (тип элемента граф.схемы),
// а порядковый номер в списке значений соответствует коду сериализации.
//
Функция ПолучитьТипыЭлементов()
    сптэ=Новый СписокЗначений;
    сптэ.Добавить(Тип("ЭлементГрафическойСхемыДекорация"),"Декорация");
    сптэ.Добавить(Тип("ЭлементГрафическойСхемыДекоративнаяЛиния"),"Линия");
    сптэ.Добавить(Тип("ЭлементГрафическойСхемыСтарт"),"Начало");
    сптэ.Добавить(Тип("ЭлементГрафическойСхемыЗавершение"),"Завершение");
    сптэ.Добавить(Тип("ЭлементГрафическойСхемыУсловие"),"Условие");
    сптэ.Добавить(Тип("ЭлементГрафическойСхемыДействие"),"Действие");
    сптэ.Добавить(Тип("ЭлементГрафическойСхемыВыборВарианта"),"Выбор варианта");
    сптэ.Добавить(Тип("ЭлементГрафическойСхемыРазделение"),"Разделение");
    сптэ.Добавить(Тип("ЭлементГрафическойСхемыСлияние"),"Слияние");
    сптэ.Добавить(Тип("ЭлементГрафическойСхемыОбработка"),"Обработка");
    сптэ.Добавить(Тип("ЭлементГрафическойСхемыВложенныйБизнесПроцесс"),"Вложенный БП");
    Возврат сптэ;
КонецФункции

&НаКлиенте
// Возвращает соответствие, где ключ - значение типа ТипСтороныЭлементаГрафическойСхемы, а значение - число.
// Значения чисел и их смысл: 
//    1 - влево, 2 - вверх, 
//    3, 5, 7, 9, 11 итд - вправо (3 в блоках и условиях, 5 в обычных блоках, 7 и более в выборе вариантов);
//    4 - вниз, 6 и 8 - ???
//
Функция ПолучитьТипыСторонЭлементов()
    соот=Новый Соответствие;
    соот.Вставить(ТипСтороныЭлементаГрафическойСхемы.Лево,1);
    соот.Вставить(ТипСтороныЭлементаГрафическойСхемы.Верх,2);
    соот.Вставить(ТипСтороныЭлементаГрафическойСхемы.Право,3);
    соот.Вставить(ТипСтороныЭлементаГрафическойСхемы.Низ,4);
    Возврат соот;
КонецФункции

&НаКлиенте
// Разбирает текст по элементам с именем itemId, рассматривает их как числа и возвращает значение наибольшего.
//
// Параметры:
//    рТекст - рассматриваемый текст сериализованной граф.схемы.
//
Функция ПолучитьСтаршийИдентификатор(рТекст) Экспорт
    чтен=Новый ЧтениеXML;
    чтен.УстановитьСтроку(рТекст);
    постр=Новый ПостроительDOM;
    докДом=постр.Прочитать(чтен);
    спис=докДом.ПолучитьЭлементыПоИмени("itemId");
    максИд=0;
    Для каждого знч Из спис Цикл
        Попытка чисИд=Число(СокрЛП(знч.ТекстовоеСодержимое)) Исключение чисИд=0 КонецПопытки;
        максИд=Макс(максИд,чисИд);
    КонецЦикла;
    Возврат максИд+1;
КонецФункции

&НаКлиенте
// Возвращает строку, содержащую теги, описывающие фигуру элемента графической схемы согласно её типу.
// Обычно вызывается из ДобавитьФигуру и самостоятельно не употребляется.
// При ошибке возвращает пустую строку.
//
// Параметры:
//    рТипЭлемента - числовой тип элемента граф.схемы; должен быть ранее преобразован из типа Тип, если надо;
//    рКоординатыКонтура - структура, обязательно уже содержащая ключи Верх, Низ, Лево, Право с числовыми значениями;
//        если этих значений нет, то выполняется попытка их автоопределить (для линии их можно пропускать, найдёт сама по
//        данным объекта-откуда и объекта-куда). Вместо "Низ" можно указывать "Высота"; вместо "Право" можно "Ширина";
//        для линий можно задать только ключи "СерединаГор" и "СерединаВерт", координаты средней точки линии, что бывает
//        нужно для диагонально-ориентированных линий.
//
Функция ДобавитьКоординатыФигуры(рТипЭлемента,рКоординатыКонтура)
Попытка
    рВерх=рКоординатыКонтура.Верх;
    рНиз=рКоординатыКонтура.Низ;
    рЛево=рКоординатыКонтура.Лево;
    рПраво=рКоординатыКонтура.Право;
    рСерединаГор=рЛево+(рПраво-рЛево)/2;
    рСерединаВер=рВерх+(рНиз-рВерх)/2;
    //
    сс="";
    Если рТипЭлемента=1 Тогда // декор.линия
        х=рЛево; у=рВерх;     сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        Если рКоординатыКонтура.Свойство("СерединаГор") Тогда
            х=рКоординатыКонтура.СерединаГор;
        Иначе
            х=рСерединаГор; 
        КонецЕсли;
        Если рКоординатыКонтура.Свойство("СерединаВерт") Тогда
            у=рКоординатыКонтура.СерединаВерт;
        Иначе
            у=рСерединаВер;
        КонецЕсли;
        сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рПраво-1; у=рНиз-1; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
    ИначеЕсли рТипЭлемента=2 Тогда // начало
        х=рЛево; у=рВерх;     сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";        
        х=рПраво-1; у=рВерх; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рПраво-1; у=рСерединаВер; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рСерединаГор; у=рНиз-1; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рЛево; у=рСерединаВер; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
    ИначеЕсли рТипЭлемента=3 Тогда // завершение
        х=рСерединаГор; у=рВерх; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рПраво-1; у=рСерединаВер; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рПраво-1; у=рНиз-1; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рЛево; у=рНиз-1; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рЛево; у=рСерединаВер; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
    ИначеЕсли рТипЭлемента=4 Тогда // условие
        х=рЛево; у=рСерединаВер; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рЛево+11; у=рВерх; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рПраво-12; у=рВерх; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рПраво-1; у=рСерединаВер; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рПраво-12; у=рНиз-1; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рЛево+11; у=рНиз-1; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
    ИначеЕсли рТипЭлемента=7 Тогда // разделение
        х=рЛево; у=рВерх; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рПраво-1; у=рВерх; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рСерединаГор; у=рНиз-1; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
    ИначеЕсли рТипЭлемента=8 Тогда // слияние
        х=рЛево; у=рНиз-1; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рПраво-1; у=рНиз-1; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рСерединаГор; у=рВерх; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
    Иначе // действие, вариант, обработка, вложенный БП
        х=рЛево; у=рВерх; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рПраво-1; у=рВерх; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рПраво-1; у=рНиз-1; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
        х=рЛево; у=рНиз-1; сс=сс+"<point><x>"+Строка(х)+"</x><y>"+Строка(у)+"</y></point>";
    КонецЕсли;
    //
    Возврат сс;
Исключение
    Сообщить("ДобавитьКоординатыФигуры, ошибка: "+ОписаниеОшибки());
    Возврат "";
КонецПопытки;
КонецФункции

&НаКлиенте
// Готовит фрагмент xml-текста согласно указанным параметрам; внутри себя дописывает этот фрагмент в общую строку всей схемы.
// Возвращает строку фрагмента, соответствующую добавленному элементу графической схемы (фигуре).
// При ошибке возвращает пустую строку.
//
// Параметры:
//    строГС - строка сериализованной схемы в целом; изменяется внутри функции;
//    пар (структура), описание см.ниже в области "ОписаниеПараметров":
//
#Область ОписаниеПараметров

#Область ОбщиеДляВсехЭлементов
    //   Имя (строка), 
    //   ТипЭлемента (тип, строка или число от 0 до 10 - имя типа элемента ГС в нотации 1С или числовой идентификатор)
    //   [Идентификатор] (число, полученное, например, с помощью ПолучитьСтаршийИдентификатор, itemId), 
    //   ТекстЗаголовка (строка), 
    //   [ТекстПодсказки] (строка), 
    //   [НомерВОбходе] (число; может совпадать с Идентификатор), 
    //   [Гиперссылка] (булево),
    //   [Прозрачность] (булево),
    //   [ГоризонтальноеПоложение] (ГоризонтальноеПоложение),
    //   [ВертикальноеПоложение] (ВертикальноеПоложение),
    //   [ПоложениеКартинки] (ПоложениеКартинкиЭлементаГрафическойСхемы),
    //   КоординатыКонтура (структура с числовыми значениями ключей: Лево,Верх,Право,Низ или Лево,Верх,Ширина,Высота, причём
    //       при задании Право, Низ правая граница считается относительно 0, а не левой, и нижняя граница - относительно 0, а не верхней.
    //       для линий это необязательный параметр; при его отсутствии линия пытается определиться по Откуда/Куда 
    //       и НаправлениеОткуда/НаправлениеКуда; при его наличии Лево,Верх это начальная точка линии, а Право,Низ - конечная; причём
    //       задание через Ширина и Высота также приведёт к нужному результату.
    //    Изменение координат контура выполняется с изменением коллекции параметров.
    //
#КонецОбласти

#Область ДляДекорации
    //   Фигура (ФигурыГрафическойСхемы)
#КонецОбласти

#Область ДляЛинии
    //   Откуда (число) - идентификатор (itemId) элемента, откуда идёт линия, если ниоткуда не идёт, то -1
    //   Куда (число) - дентификатор (itemId) элемента, куда идёт линия, если никуда не идёт, то -1
    //   ВариантОткуда (для линий, выходящих из выбора варианта, № варианта (нач.с 0),
    //   [ДекоративнаяЛиния] (булево),
    //   [ПоложениеТекста] (ПоложениеТекстаСоединительнойЛинии),
    //   [СтильСтрелкиНачало] (СтильСтрелки),
    //   [СтильСтрелкиКонец] (СтильСтрелки),
    //   НаправлениеОткуда (числовой номер визуального направления отправителя; край, откуда выходит линия),
    //   НаправлениеКуда (числовой номер визуального направления получателя; край, куда входит линия),
    //         т.е. это стороны объектов, связанных линией, куда прикрепляется линия тем или иным своим концом:
    //         1 - влево, 2 - вверх, 
    //         3, 5, 7, 9, 11 итд - вправо (3 в блоках и условиях, 5 в обычных блоках, 7 и более в выборе вариантов);
    //         4 - вниз, 6 и 8 - ???
    //         или значение типа ТипСтороныЭлементаГрафическойСхемы.
    //   Если указано направление типа ТипСтороныЭлементаГрафическойСхемы, то оно преобразуется в число также и в параметрах.
#КонецОбласти

#Область ДляУсловия
    // выход ветки (1 - влево, 3 - вправо)
    //   [НаправлениеВеткиДа] (число),
    //   [НаправлениеВеткиНет] (число).
#КонецОбласти

#Область ДляДействия
    //   ОписаниеДействия (строка), 
    //   АдресацияДействия (строка), 
    //   [ГрупповаяАдресация] (булево), 
    //   [ВысотаОбластиАдресации] (число)
#КонецОбласти

#Область ДляВыбораВарианта
    //  Варианты - массив структур: Идентификатор (строка), ТекстЗаголовка (строка), Куда (идентификатор получателя стрелки), НаправлениеКуда (его боковина)
#КонецОбласти

#Область ДляВложенногоБП
    //   ТекстЗаголовкаБП (строка)
#КонецОбласти

#КонецОбласти
//
//    также по ходу работы в структуру "пар" добавляются или могут для оптимизации быть указаны заранее:
//        СписокТиповЭлементов - список значений, согласно функции ПолучитьТипыЭлементов();
//        ТипыСторонЭлементов - соответствие, согласно функции ПолучитьТипыСторонЭлементов(); вносится только при добавлении линий.
//    соотДобавленных - соответствие, где ключи - числовые ID элементов, а значения - структуры параметров их построения.
//        
Функция ДобавитьФигуру(строГС,пар,соотДобавленных=Неопределено)
Попытка
    Если ТипЗнч(соотДобавленных)<>Тип("Соответствие") Тогда соотДобавленных=Новый Соответствие КонецЕсли;
    
    #Область ОбработкаТипаИИдентификатора
    
    рТипЭлемента=ТипЗнч(пар.ТипЭлемента);
    Если рТипЭлемента=Тип("Строка") Тогда
        Попытка чисТип=Число(СокрЛП(пар.ТипЭлемента)) Исключение чисТип=-1 КонецПопытки;
        Если чисТип=-1 Тогда
            // передано имя типа элемента в нотации 1С, преобразуем в идентификатор
            Если пар.Свойство("СписокТиповЭлементов") Тогда
                сптэ=пар.СписокТиповЭлементов;
            Иначе // получим "по месту" и занесём в параметры
                сптэ=ПолучитьТипыЭлементов();
                пар.Вставить("СписокТиповЭлементов",сптэ);
            КонецЕсли;
            пози=сптэ.НайтиПоЗначению(Тип(СокрЛП(пар.ТипЭлемента)));
            Если пози=Неопределено Тогда
                Сообщить("ДобавитьФигуру: не удалось найти идентификатор типа """+СокрЛП(пар.ТипЭлемента)+", фигура не добавляется!",СтатусСообщения.Важное);
                Возврат "";
            КонецЕсли;        
            рТипЭлемента=сптэ.Индекс(пози);
        Иначе
            // передан сразу идентификатор; проверять не будем, сразу вставляем
            рТипЭлемента=чисТип;
        КонецЕсли;        
    ИначеЕсли рТипЭлемента=Тип("Тип") Тогда
        // передан тип элемента (удобнее писать с использованием подсказок 1С), преобразуем в идентификатор
        Если пар.Свойство("СписокТиповЭлементов") Тогда
            сптэ=пар.СписокТиповЭлементов;
        Иначе // получим "по месту" и занесём в параметры
            сптэ=ПолучитьТипыЭлементов();
            пар.Вставить("СписокТиповЭлементов",сптэ);
        КонецЕсли;
        пози=сптэ.НайтиПоЗначению(пар.ТипЭлемента);
        Если пози=Неопределено Тогда
            Сообщить("ДобавитьФигуру: не удалось найти идентификатор типа """+СокрЛП(пар.ТипЭлемента)+", фигура не добавляется!",СтатусСообщения.Важное);
            Возврат "";
        КонецЕсли;        
        рТипЭлемента=сптэ.Индекс(пози);
    ИначеЕсли рТипЭлемента=Тип("Число") Тогда
        // передан сразу идентификатор; проверять не будем, сразу вставляем
        рТипЭлемента=пар.ТипЭлемента;
    КонецЕсли;
    Если рТипЭлемента<0 или рТипЭлемента>10 Тогда Возврат "" КонецЕсли;
    //
    Если не пар.Свойство("Идентификатор") Тогда // получаем "по месту" как старшего и занесём в параметры
        // при такой идеологии работы важно потом переустановить/сбросить значение этого параметра!
        рИдентификатор=ПолучитьСтаршийИдентификатор(строГС);
        пар.Вставить("Идентификатор",рИдентификатор);
    Иначе
        рИдентификатор=пар.Идентификатор;
    КонецЕсли;    
    
    #КонецОбласти
    
    фБул="БЛ=false; БИ=true";
    
    сс="
    |<item>";
    
    #Область ДобавлениеОбщихСвойств
        
    // общие свойства
    сс=сс+"
    |<itemType>"+СокрЛП(рТипЭлемента)+"</itemType>
    |<itemId>"+СокрЛП(рИдентификатор)+"</itemId>
    |<currentLanguage>#</currentLanguage>
    |<itemTitle><item xmlns=""http://v8.1c.ru/8.1/data/core""><lang>#</lang>
    |<content>"+пар.ТекстЗаголовка+"</content></item></itemTitle>
    |<tipText><item xmlns=""http://v8.1c.ru/8.1/data/core""><lang>#</lang>
    |<content>"+?(пар.Свойство("ТекстПодсказки"),пар.ТекстПодсказки,"")+"</content></item></tipText>
    |<itemCode>"+пар.Имя+"</itemCode>
    |<itemTabOrder>"+СокрЛП(?(пар.Свойство("НомерВОбходе"),пар.НомерВОбходе,рИдентификатор))+"</itemTabOrder>
    // // пар.Оформление.ЦветФона,  // пар.Оформление.ЦветТекста,  // пар.Оформление.ЦветЛинии,  // пар.Оформление.Шрифт
    |<backColor>auto</backColor>
    |<textColor xmlns:d3p1=""http://v8.1c.ru/8.1/data/ui/style"">d3p1:FormTextColor</textColor>
    |<lineColor xmlns:d3p1=""http://v8.1c.ru/8.1/data/ui/style"">d3p1:BorderColor</lineColor>
    |<groupNum>0</groupNum>
    |<zOrder>"+СокрЛП(?(пар.Свойство("НомерВОбходе"),пар.НомерВОбходе,рИдентификатор))+"</zOrder>
    |<hyperlink>"+?(пар.Свойство("Гиперссылка"),Формат(пар.Гиперссылка,фБул),"false")+"</hyperlink>
    |<transparent>"+?(пар.Свойство("Прозрачность"),Формат(пар.Прозрачность,фБул),"false")+"</transparent>
    |<textFont kind=""AutoFont""/>
    |<alignHor>"+?(пар.Свойство("ГоризонтальноеПоложение"),АнглИмя(пар.ГоризонтальноеПоложение),"Center")+"</alignHor>
    |<alignVer>"+?(пар.Свойство("ВертикальноеПоложение"),АнглИмя(пар.ВертикальноеПоложение),"Center")+"</alignVer>
    |<picturePlacement>"+?(пар.Свойство("ПоложениеКартинки"),АнглИмя(пар.ПоложениеКартинки),"Left")+"</picturePlacement>
    // работу с картинками пока не реализуем
    |<picture/>
    |<pictureStyle>4</pictureStyle>
    // pictureStyle - порядковый номер значения сис.перечисления РазмерКартинки, как он задан не в СП, а в списке выбора палитры свойств, 4 - АвтоРазмер
    //<pointUUID>GUIDОбъекта</pointUUID>
    |";
    
    #КонецОбласти
    
    #Область ДополнительнаяПодготовка
    
    Если рТипЭлемента=1 Тогда
        рНаправлениеОткуда=пар.НаправлениеОткуда;
        Если ТипЗнч(рНаправлениеОткуда)=Тип("ТипСтороныЭлементаГрафическойСхемы") Тогда
            Если пар.Свойство("ТипыСторонЭлементов") Тогда
                соотНапр=пар.ТипыСторонЭлементов;
            Иначе
                соотНапр=ПолучитьТипыСторонЭлементов();
                пар.Вставить("ТипыСторонЭлементов",соотНапр);
            КонецЕсли;
            рНаправлениеОткуда=соотНапр.Получить(рНаправлениеОткуда);
            Если рНаправлениеОткуда=Неопределено Тогда рНаправлениеОткуда=4 КонецЕсли; // из нижней
            пар.Вставить("НаправлениеОткуда",рНаправлениеОткуда);
        КонецЕсли;
        //
        рНаправлениеКуда=пар.НаправлениеКуда;
        Если ТипЗнч(рНаправлениеКуда)=Тип("ТипСтороныЭлементаГрафическойСхемы") Тогда
            Если пар.Свойство("ТипыСторонЭлементов") Тогда
                соотНапр=пар.ТипыСторонЭлементов;
            Иначе
                соотНапр=ПолучитьТипыСторонЭлементов();
                пар.Вставить("ТипыСторонЭлементов",соотНапр);
            КонецЕсли;
            рНаправлениеКуда=соотНапр.Получить(рНаправлениеКуда);
            Если рНаправлениеКуда=Неопределено Тогда рНаправлениеКуда=4 КонецЕсли; // из нижней
            пар.Вставить("НаправлениеКуда",рНаправлениеКуда);            
        КонецЕсли;
        //
    Иначе
        // эти параметры задём статично (более частные свойства)
        //сс=сс+"
        //|<passageState>0</passageState>
        //|<tableCode>34</tableCode>
        //|<bpPointValue xmlns:d3p1="http://v8.1c.ru/8.1/data/enterprise/current-config" xsi:type="d3p1:BusinessProcessRoutePointRef.БизнесПроцесс1">18c0a78b-c146-4790-86b7-9f833864fadf</bpPointValue>
        //|";
        //
    КонецЕсли;
    
    #КонецОбласти
    
    #Область ДобавлениеКонтураИКоординат
    
    // очерчиваем область, где будет расположен элемент (для линии могут быть не заданы)
    рКоординатыБылиЗаданы=Истина;
    рКоординатыОткудаЗаданы=Истина; 
    рКоординатыКудаЗаданы=Истина;
    //
    Если не пар.Свойство("КоординатыКонтура") Тогда
        рКоординатыБылиЗаданы=Ложь;
        рКоординатыОткудаЗаданы=Ложь; 
        рКоординатыКудаЗаданы=Ложь;
        пар.Вставить("КоординатыКонтура",Новый Структура);
    Иначе
        Если не пар.КоординатыКонтура.Свойство("Ширина") 
        и не пар.КоординатыКонтура.Свойство("Высота")
        и не пар.КоординатыКонтура.Свойство("Лево")
        и не пар.КоординатыКонтура.Свойство("Право")
        и не пар.КоординатыКонтура.Свойство("Верх")
        и не пар.КоординатыКонтура.Свойство("Низ")
        Тогда
            // переданы, возможно, только координаты середины линии, а остальное надо автоопределить
            рКоординатыБылиЗаданы=Ложь;
        КонецЕсли;
        Если не пар.КоординатыКонтура.Свойство("Лево") и не пар.КоординатыКонтура.Свойство("Верх") Тогда
            рКоординатыОткудаЗаданы=Ложь;
        КонецЕсли;        
        Если (не пар.КоординатыКонтура.Свойство("Ширина") и не пар.КоординатыКонтура.Свойство("Право"))
        или (не пар.КоординатыКонтура.Свойство("Высота") и не пар.КоординатыКонтура.Свойство("Низ"))
        Тогда 
            рКоординатыКудаЗаданы=Ложь;
        КонецЕсли;
    КонецЕсли;
    //
    Если пар.КоординатыКонтура.Свойство("Ширина") и не пар.КоординатыКонтура.Свойство("Право") Тогда 
        пар.КоординатыКонтура.Вставить("Право",пар.КоординатыКонтура.Лево+пар.КоординатыКонтура.Ширина);
    КонецЕсли;
    Если пар.КоординатыКонтура.Свойство("Высота") и не пар.КоординатыКонтура.Свойство("Низ") Тогда 
        пар.КоординатыКонтура.Вставить("Низ",пар.КоординатыКонтура.Верх+пар.КоординатыКонтура.Высота);
    КонецЕсли;
    //
    Если рТипЭлемента=1 Тогда // линия
        Если не рКоординатыБылиЗаданы или не рКоординатыОткудаЗаданы Тогда
            Попытка рОткуда=соотДобавленных.Получить(пар.Откуда) Исключение рОткуда=Неопределено КонецПопытки;
            Если рОткуда<>Неопределено Тогда
                рЛево=-1; рВерх=-1;
                Если пар.НаправлениеОткуда=1 Тогда // выходим влево, нужна середина левой границы
                    рЛево=рОткуда.КоординатыКонтура.Лево;
                    рВерх=рОткуда.КоординатыКонтура.Верх+(рОткуда.КоординатыКонтура.Низ-рОткуда.КоординатыКонтура.Верх)/2;
                ИначеЕсли пар.НаправлениеОткуда=2 Тогда // выходим вверх, нужна середина верхней границы
                    рЛево=рОткуда.КоординатыКонтура.Лево+(рОткуда.КоординатыКонтура.Право-рОткуда.КоординатыКонтура.Лево)/2;
                    рВерх=рОткуда.КоординатыКонтура.Верх;
                ИначеЕсли пар.НаправлениеОткуда=3 или пар.НаправлениеОткуда=5 Тогда // выходим вправо стандартно, середина правой границы
                    рЛево=рОткуда.КоординатыКонтура.Право;
                    рВерх=рОткуда.КоординатыКонтура.Верх+(рОткуда.КоординатыКонтура.Низ-рОткуда.КоординатыКонтура.Верх)/2;
                ИначеЕсли пар.НаправлениеОткуда=4 Тогда // выходим вниз, нужна середина нижней границы
                    рЛево=рОткуда.КоординатыКонтура.Лево+(рОткуда.КоординатыКонтура.Право-рОткуда.КоординатыКонтура.Лево)/2;
                    рВерх=рОткуда.КоординатыКонтура.Низ;
                КонецЕсли;
                Если рЛево<>-1 Тогда пар.КоординатыКонтура.Вставить("Лево",рЛево) КонецЕсли;
                Если рВерх<>-1 Тогда пар.КоординатыКонтура.Вставить("Верх",рВерх) КонецЕсли;
            КонецЕсли;
        КонецЕсли;
        //
        Если не рКоординатыБылиЗаданы или не рКоординатыКудаЗаданы Тогда            
            Попытка рКуда=соотДобавленных.Получить(пар.Куда) Исключение рКуда=Неопределено КонецПопытки;
            Если рКуда<>Неопределено Тогда
                рПраво=-1; рНиз=-1;
                Если пар.НаправлениеКуда=1 Тогда // входим влево, нужна середина левой границы
                    рПраво=рКуда.КоординатыКонтура.Лево;
                    рНиз=рКуда.КоординатыКонтура.Верх+(рКуда.КоординатыКонтура.Низ-рКуда.КоординатыКонтура.Верх)/2;
                ИначеЕсли пар.НаправлениеКуда=2 Тогда // входим вверх, нужна середина верхней границы
                    рПраво=рКуда.КоординатыКонтура.Лево+(рКуда.КоординатыКонтура.Право-рКуда.КоординатыКонтура.Лево)/2;
                    рНиз=рКуда.КоординатыКонтура.Верх;
                ИначеЕсли пар.НаправлениеКуда=3 или пар.НаправлениеКуда=5 Тогда // входим вправо стандартно, середина правой границы
                    рПраво=рКуда.КоординатыКонтура.Право;
                    рНиз=рКуда.КоординатыКонтура.Верх+(рКуда.КоординатыКонтура.Низ-рКуда.КоординатыКонтура.Верх)/2;
                ИначеЕсли пар.НаправлениеКуда=4 Тогда // входим вниз, нужна середина нижней границы
                    рПраво=рКуда.КоординатыКонтура.Лево+(рКуда.КоординатыКонтура.Право-рКуда.КоординатыКонтура.Лево)/2;
                    рНиз=рКуда.КоординатыКонтура.Низ;
                КонецЕсли;
                Если рПраво<>-1 Тогда пар.КоординатыКонтура.Вставить("Право",рПраво) КонецЕсли;
                Если рНиз<>-1 Тогда пар.КоординатыКонтура.Вставить("Низ",рНиз) КонецЕсли;
            КонецЕсли;
        КонецЕсли;
        //
    Иначе
        // не линия, т.е. имеет контур
        Попытка
            сс=сс+"
            |<rectLeft>"+СокрЛП(пар.КоординатыКонтура.Лево)+"</rectLeft>
            |<rectRight>"+СокрЛП(пар.КоординатыКонтура.Право)+"</rectRight> 
            |<rectTop>"+СокрЛП(пар.КоординатыКонтура.Верх)+"</rectTop>
            |<rectBottom>"+СокрЛП(пар.КоординатыКонтура.Низ)+"</rectBottom>";
        Исключение
            Сообщить("Ошибка получения координат контура: "+ОписаниеОшибки());
            Возврат "";
        КонецПопытки;        
    КонецЕсли;
    // рисуем реальные координаты фигур (актуально для всех, в т.ч. прямоугольных и линии)
    сс=сс+ДобавитьКоординатыФигуры(рТипЭлемента,пар.КоординатыКонтура);
    
    #КонецОбласти
    
    // возможно, доделать это место!
    сс=сс+"
    |<border width=""1"" gap=""false"">
    |  <style xmlns=""http://v8.1c.ru/8.1/data/ui"" xmlns:d4p1=""http://v8.1c.ru/8.2/data/graphscheme"" xsi:type=""d4p1:ConnectorLineType"">Solid</style>
    |</border>";    

    #Область ДобавлениеСпецифическихСвойств
    
    Если рТипЭлемента=0 Тогда // декорация
        сс=сс+"        
        |<shape>"+АнглИмя(пар.Фигура)+"</shape>
        |<flipMode>0</flipMode>
        |<angle xsi:type=""xs:decimal"">0</angle>"; // вероятно, поворот вокруг своей оси
        
    ИначеЕсли рТипЭлемента=1 Тогда // линия
        сс=сс+"
        |<connectFromItemId>"+СокрЛП(пар.Откуда)+"</connectFromItemId>
        |<connectFromPortIndex>"+СокрЛП(пар.ВариантОткуда)+"</connectFromPortIndex>
        |<connectToItemId>"+СокрЛП(пар.Куда)+"</connectToItemId>
        |<decorativeLine>"+?(пар.Свойство("ДекоративнаяЛиния"),Формат(пар.ДекоративнаяЛиния,фБул),"false")+"</decorativeLine>
        |<portIndexFrom>"+СокрЛП(пар.НаправлениеОткуда)+"</portIndexFrom>
        |<portIndexTo>"+СокрЛП(пар.НаправлениеКуда)+"</portIndexTo>
        |<textPos>"+?(пар.Свойство("ПоложениеТекста"),АнглИмя(пар.ПоложениеТекста),"FirstSegment")+"</textPos>
        |<beginArrowStyle>"+?(пар.Свойство("СтильСтрелкиНачало"),АнглИмя(пар.СтильСтрелкиНачало),"None")+"</beginArrowStyle>
        |<endArrowStyle>"+?(пар.Свойство("СтильСтрелкиКонец"),АнглИмя(пар.СтильСтрелкиКонец),"Filled")+"</endArrowStyle>";
        
    ИначеЕсли рТипЭлемента=2 Тогда // начало
        // специальных нет
        
    ИначеЕсли рТипЭлемента=3 Тогда // завершение
        // специальных нет
        
    ИначеЕсли рТипЭлемента=4 Тогда // условие
        сс=сс+"        
        //<eventHandler>
        //   <id>0</id>
        //   <name>БлокУсловияПроверкаУсловия</name>
        ///eventHandler>        
        // выход ветки Нет (1 - влево, 3 - вправо)
        |<truePortIndex>"+?(пар.Свойство("НаправлениеВеткиДа"),Строка(пар.НаправлениеВеткиДа),"3")+"</truePortIndex>
        |<falsePortIndex>"+?(пар.Свойство("НаправлениеВеткиНет"),Строка(пар.НаправлениеВеткиНет),"1")+"</falsePortIndex>";
        
    ИначеЕсли рТипЭлемента=5 Тогда // действие
        сс=сс+"
        |<taskDescription>"+пар.ОписаниеДействия+"</taskDescription>
        |<explanation>"+пар.АдресацияДействия+"</explanation>
        |<groupAddressing>"+?(пар.Свойство("ГрупповаяАдресация"),Формат(пар.ГрупповаяАдресация,фБул),"false")+"</groupAddressing>
        // значение разделения на область адресации и область описания, ставим всегда Истина
        |<isAddrZoneDivideValid>true</isAddrZoneDivideValid>
        // позиция разделителя по высоте между областью адресации и описанием действия
        |<addrZoneDivideYPos>"+Строка(?(пар.Свойство("ВысотаОбластиАдресации"),пар.ВысотаОбластиАдресации,16))+"</addrZoneDivideYPos>
        |";
        
    ИначеЕсли рТипЭлемента=6 Тогда // выбор варианта
        квоВариантов=пар.Варианты.Количество();
        Для й=0 По квоВариантов-1 Цикл
            рВариант=пар.Варианты.Получить(й);
            сс=сс+"
            |<transition>
            |<name>"+рВариант.Идентификатор+"</name>
            |<description><item xmlns=""http://v8.1c.ru/8.1/data/core""><lang>#</lang>
            |<content>"+рВариант.ТекстЗаголовка+"</content></item></description>
            |<backColor>auto</backColor>
            |</transition>";
            //
            // добавляем линию с координатой, начинающейся от середины варианта
            //парПолучателяЛинии=соотДобавленных.Получить(рВариант.Куда); - если надо получитьэти данные
            парЛВ=Новый Структура;
            парЛВ.Вставить("Имя","ЛинияВарианта"+рВариант.Идентификатор);
            парЛВ.Вставить("ТипЭлемента","ЭлементГрафическойСхемыДекоративнаяЛиния");
            парЛВ.Вставить("Идентификатор",ПолучитьСтаршийИдентификатор(строГС));
            парЛВ.Вставить("ТекстЗаголовка","");
            парЛВ.Вставить("Откуда",рИдентификатор);
            парЛВ.Вставить("Куда",рВариант.Куда); // идентификатор элемента, куда должна вести стрелка от варианта
            парЛВ.Вставить("ВариантОткуда",0);
            парЛВ.Вставить("ДекоративнаяЛиния",Истина);
            парЛВ.Вставить("ПоложениеТекста",ПоложениеТекстаСоединительнойЛинии.СерединаЛинии);
            парЛВ.Вставить("НаправлениеОткуда",ТипСтороныЭлементаГрафическойСхемы.Право); // всегда
            парЛВ.Вставить("НаправлениеКуда",?(ЗначениеЗаполнено(рВариант.НаправлениеКуда),рВариант.НаправлениеКуда,ТипСтороныЭлементаГрафическойСхемы.Верх));
            рКоординатыЛинии=Новый Структура;
            рКоординатыЛинии.Вставить("Лево",пар.КоординатыКонтура.Право);
            рКоординатыЛинии.Вставить("Верх",пар.КоординатыКонтура.Низ-9-18*(квоВариантов-1-й));
            парЛВ.Вставить("КоординатыКонтура",рКоординатыЛинии);
            ДобавитьФигуру(строГС,парЛВ,соотДобавленных);
        КонецЦикла;
        
        //<eventHandler>
        //    <id>0</id>
        //    <name>БлокВыборВариантаОбработкаВыбораВарианта</name>
        //</eventHandler>
        
    ИначеЕсли рТипЭлемента=7 Тогда // точка разделения
        // специальных нет
        
    ИначеЕсли рТипЭлемента=8 Тогда // точка слияния
        // специальных нет
        
    ИначеЕсли рТипЭлемента=9 Тогда // обработка
        // специальных нет
        
    ИначеЕсли рТипЭлемента=10 Тогда // вложенный процесс
        //<subprocessUUID>a5f642e1-d2ab-4106-b6dc-d6f85222c430</subprocessUUID>
        сс=сс+"
        |<taskDescription>"+пар.ТекстЗаголовкаБП+"</taskDescription>";
        
    КонецЕсли;
    
    #КонецОбласти

    сс=сс+"
    |</item>";
    
    строГС=СтрЗаменить(строГС,"<!--ReplacingPoint-->",сс+Символы.ПС+"<!--ReplacingPoint-->");
    
    соотДобавленных.Вставить(рИдентификатор,пар);

    Возврат сс;
    
Исключение
    Сообщить("ДобавитьФигуру, ошибка: "+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
    Возврат "";
КонецПопытки;
КонецФункции

&НаКлиенте
// Добавляет упрощённый вариант соединительной декоративной линии между элементами ГС.
// Все значения линии ставятся по умолчанию.
// Возвращает кусок строки, соответствующий линии, аналогично ДобавитьФигуру для неё.
// При ошибке возвращает пустую строку.
//
// Параметры:
//    строГС - строка сериализованной схемы в целом; изменяется внутри функции;
//    соотДобавленных - соответствие, где ключи - числовые ID элементов, а значения - структуры параметров их построения;
//    рОткуда - идентификатор или строковое имя элемента, откуда начинается линия;
//    рКуда - идентификатор или строковое имя элемента, где заканчивается линия;
//    рНаправление - строковое указание, как в целом направлена линия (допустимы Вверх, Вниз, Влево, Вправо).
//
Функция СоединитьФигурыЛинией(строГС,соотДобавленных,рОткуда,рКуда,рНаправление="Вниз")
Попытка
    пар=Новый Структура;
    //
    Если рНаправление="Влево" Тогда
        пар.Вставить("НаправлениеОткуда",ТипСтороныЭлементаГрафическойСхемы.Право);
        пар.Вставить("НаправлениеКуда",ТипСтороныЭлементаГрафическойСхемы.Лево);
    ИначеЕсли рНаправление="Вправо" Тогда
        пар.Вставить("НаправлениеОткуда",ТипСтороныЭлементаГрафическойСхемы.Лево);
        пар.Вставить("НаправлениеКуда",ТипСтороныЭлементаГрафическойСхемы.Право);
    ИначеЕсли рНаправление="Вниз" Тогда
        пар.Вставить("НаправлениеОткуда",ТипСтороныЭлементаГрафическойСхемы.Низ);
        пар.Вставить("НаправлениеКуда",ТипСтороныЭлементаГрафическойСхемы.Верх);
    ИначеЕсли рНаправление="Вверх" Тогда
        пар.Вставить("НаправлениеОткуда",ТипСтороныЭлементаГрафическойСхемы.Верх);
        пар.Вставить("НаправлениеКуда",ТипСтороныЭлементаГрафическойСхемы.Низ);
    Иначе
        Возврат "";
    КонецЕсли;
    //
    Если ТипЗнч(рОткуда)=Тип("Строка") Тогда // это имя откуда, получаем ид
        Для каждого киз Из соотДобавленных Цикл
            Если киз.Значение.Имя=рОткуда Тогда рОткуда=киз.Ключ; Прервать КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    Если ТипЗнч(рКуда)=Тип("Строка") Тогда // это имя куда, получаем ид
        Для каждого киз Из соотДобавленных Цикл
            Если киз.Значение.Имя=рКуда Тогда рКуда=киз.Ключ; Прервать КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    //
    ид=ПолучитьСтаршийИдентификатор(строГС);
    пар.Вставить("Имя","Линия"+Строка(ид));
    пар.Вставить("ТипЭлемента","ЭлементГрафическойСхемыДекоративнаяЛиния");
    пар.Вставить("Идентификатор",ид);
    пар.Вставить("ТекстЗаголовка","");
    пар.Вставить("Откуда",рОткуда);
    пар.Вставить("Куда",рКуда);
    пар.Вставить("ВариантОткуда",0);
    пар.Вставить("ДекоративнаяЛиния",Истина);
    Возврат ДобавитьФигуру(строГС,пар,соотДобавленных);
Исключение
    Сообщить("СоединитьФигурыЛинией, ошибка: "+ОписаниеОшибки());
    Возврат "";
КонецПопытки;
КонецФункции

&НаКлиенте
// Готовит общее объявление пустой графической схемы с общими свойствами
//   [ИспользоватьСетку] (булево),
//   [РежимОтрисовкиСетки] (РежимОтрисовкиСеткиГрафическойСхемы), если не указан, и ИспользоватьСетку=Истина, то Lines.
//   [ГоризонтальныйШагСетки] (число),
//   [ВертикальныйШагСетки] (число),
//   [Вывод] (ИспользованиеВывода)
//
Функция ИнициализироватьГрафическуюСхему(пар=Неопределено)
    Если ТипЗнч(пар)<>Тип("Структура") Тогда пар=Новый Структура КонецЕсли;
    Если пар.Свойство("ИспользоватьСетку") и пар.ИспользоватьСетку и не пар.Свойство("РежимОтрисовкиСетки") Тогда
        рРежимОтрисовки="Lines";
    Иначе
        рРежимОтрисовки=?(пар.Свойство("РежимОтрисовкиСетки"),пар.РежимОтрисовкиСетки,"None");
    КонецЕсли;
    сс="<FlowchartContextType xmlns=""http://v8.1c.ru/8.2/data/graphscheme"" xmlns:xs=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
    |<backColor xmlns:d2p1=""http://v8.1c.ru/8.1/data/ui/style"">d2p1:FieldBackColor</backColor>
    |<enableGrid>"+?(пар.Свойство("ИспользоватьСетку"),Формат(пар.ИспользоватьСетку,"БЛ=false; БИ=true"),"false")+"</enableGrid>
    |<drawGridMode>"+рРежимОтрисовки+"</drawGridMode>
    |<gridHorizontalStep>"+Строка(?(пар.Свойство("ГоризонтальныйШагСетки"),СокрЛП(пар.ГоризонтальныйШагСетки),20))+"</gridHorizontalStep>
    |<gridVerticalStep>"+Строка(?(пар.Свойство("ВертикальныйШагСетки"),СокрЛП(пар.ВертикальныйШагСетки),20))+"</gridVerticalStep>
    |<bpUUID>00000000-0000-0000-0000-000000000000</bpUUID>
    |<useOutput>"+?(пар.Свойство("Вывод"),АнглИмя(пар.Вывод),"Auto")+"</useOutput>
    |<printPropItem><key>6</key><val>10</val></printPropItem>
    |<printPropItem><key>7</key><val>10</val></printPropItem>
    |<printPropItem><key>8</key><val>10</val></printPropItem>
    |<printPropItem><key>9</key><val>10</val></printPropItem>
    |<printPropItem><key>13</key><val>0</val></printPropItem>
    |<printPropItem><key>16</key><val>0</val></printPropItem>
    |<!--ReplacingPoint-->
    |</FlowchartContextType>";
    Возврат сс;
КонецФункции

#КонецОбласти



// Пример использования (он и порождает схему, представленную на картинке к публикации):

&НаКлиенте
Процедура ВывестиСхему()

    соотДобавленных=Новый Соответствие;
    
    пар=Новый Структура;
    строГС=ИнициализироватьГрафическуюСхему(пар);
    //
    идСтарт=ПолучитьСтаршийИдентификатор(строГС);
    пар=Новый Структура;
    пар.Вставить("Имя","ТестСтарта");
    пар.Вставить("ТипЭлемента","ЭлементГрафическойСхемыСтарт");
    пар.Вставить("Идентификатор",идСтарт);
    пар.Вставить("ТекстЗаголовка","Погнали!");
    пар.Вставить("КоординатыКонтура",Новый Структура("Лево,Верх,Ширина,Высота",100,30,100,40));
    ДобавитьФигуру(строГС,пар,соотДобавленных);
    
    идДействие1=ПолучитьСтаршийИдентификатор(строГС);
    пар=Новый Структура;
    пар.Вставить("Имя","ТестДействия");
    пар.Вставить("ТипЭлемента",Тип("ЭлементГрафическойСхемыДействие"));
    пар.Вставить("Идентификатор",идДействие1);
    пар.Вставить("ТекстЗаголовка","Это действие");
    пар.Вставить("КоординатыКонтура",Новый Структура("Лево,Верх,Ширина,Высота",100,120,100,60));
    пар.Вставить("ОписаниеДействия","Некое действие в системе");
    пар.Вставить("АдресацияДействия","И.И.Иванов");
    ДобавитьФигуру(строГС,пар,соотДобавленных);
    
    идУсловие=ПолучитьСтаршийИдентификатор(строГС);
    пар=Новый Структура;
    пар.Вставить("Имя","ТестУсловия");
    пар.Вставить("ТипЭлемента",Тип("ЭлементГрафическойСхемыУсловие"));
    пар.Вставить("Идентификатор",идУсловие);
    пар.Вставить("ТекстЗаголовка","А я знаю?");
    пар.Вставить("КоординатыКонтура",Новый Структура("Лево,Верх,Ширина,Высота",100,220,100,40));
    пар.Вставить("НаправлениеВеткиДа",3); // вправо
    пар.Вставить("НаправлениеВеткиНет",1); // влево
    ДобавитьФигуру(строГС,пар,соотДобавленных);
    
    идДействие2=ПолучитьСтаршийИдентификатор(строГС);
    пар=Новый Структура;
    пар.Вставить("Имя","ТестДействия2");
    пар.Вставить("ТипЭлемента",Тип("ЭлементГрафическойСхемыДействие"));
    пар.Вставить("Идентификатор",идДействие2);
    пар.Вставить("ТекстЗаголовка","Тоже что-то");
    пар.Вставить("КоординатыКонтура",Новый Структура("Лево,Верх,Ширина,Высота",10,280,100,60));
    пар.Вставить("ОписаниеДействия","Некое действие в системе");
    пар.Вставить("АдресацияДействия","Петров");
    ДобавитьФигуру(строГС,пар,соотДобавленных);
    
    пар=Новый Структура;
    пар.Вставить("Имя","ТестЛинии2");
    пар.Вставить("ТипЭлемента","ЭлементГрафическойСхемыДекоративнаяЛиния");
    пар.Вставить("Идентификатор",ПолучитьСтаршийИдентификатор(строГС));
    пар.Вставить("ТекстЗаголовка","Нет");
    пар.Вставить("Откуда",идУсловие);
    пар.Вставить("Куда",идДействие2);
    пар.Вставить("ВариантОткуда",0);
    пар.Вставить("ДекоративнаяЛиния",Истина);
    пар.Вставить("ПоложениеТекста",ПоложениеТекстаСоединительнойЛинии.ПервыйСегмент);
    пар.Вставить("СтильСтрелкиНачало",СтильСтрелки.Нет);
    пар.Вставить("СтильСтрелкиКонец",СтильСтрелки.Заполненная);
    пар.Вставить("НаправлениеОткуда",ТипСтороныЭлементаГрафическойСхемы.Лево);
    пар.Вставить("НаправлениеКуда",ТипСтороныЭлементаГрафическойСхемы.Верх);
    пар.Вставить("КоординатыКонтура",Новый Структура("СерединаГор,СерединаВерт",60,240));
    ДобавитьФигуру(строГС,пар,соотДобавленных);
    
    идОбр=ПолучитьСтаршийИдентификатор(строГС);
    пар=Новый Структура;
    пар.Вставить("Имя","ТестОбработки");
    пар.Вставить("ТипЭлемента",Тип("ЭлементГрафическойСхемыОбработка"));
    пар.Вставить("Идентификатор",идОбр);
    пар.Вставить("ТекстЗаголовка","Зашли сюды");
    пар.Вставить("КоординатыКонтура",Новый Структура("Лево,Верх,Ширина,Высота",180,290,100,60));
    ДобавитьФигуру(строГС,пар,соотДобавленных);
    
    пар=Новый Структура;
    пар.Вставить("Имя","ТестЛинии3");
    пар.Вставить("ТипЭлемента","ЭлементГрафическойСхемыДекоративнаяЛиния");
    пар.Вставить("Идентификатор",ПолучитьСтаршийИдентификатор(строГС));
    пар.Вставить("ТекстЗаголовка","Да");
    пар.Вставить("Откуда",идУсловие);
    пар.Вставить("Куда",идОбр);
    пар.Вставить("ВариантОткуда",0);
    пар.Вставить("ДекоративнаяЛиния",Истина);
    пар.Вставить("ПоложениеТекста",ПоложениеТекстаСоединительнойЛинии.ПервыйСегмент);
    пар.Вставить("СтильСтрелкиНачало",СтильСтрелки.Нет);
    пар.Вставить("СтильСтрелкиКонец",СтильСтрелки.Заполненная);
    пар.Вставить("НаправлениеОткуда",ТипСтороныЭлементаГрафическойСхемы.Право);
    пар.Вставить("НаправлениеКуда",ТипСтороныЭлементаГрафическойСхемы.Верх);
    ДобавитьФигуру(строГС,пар,соотДобавленных);
    
    идСтоп=ПолучитьСтаршийИдентификатор(строГС);
    пар=Новый Структура;
    пар.Вставить("Имя","ТестСтопа");
    пар.Вставить("ТипЭлемента","ЭлементГрафическойСхемыЗавершение");
    пар.Вставить("Идентификатор",идСтоп);
    пар.Вставить("ТекстЗаголовка","Тпрууу!");
    пар.Вставить("КоординатыКонтура",Новый Структура("Лево,Верх,Ширина,Высота",740,210,100,40));
    ДобавитьФигуру(строГС,пар,соотДобавленных);
    
    идБП1=ПолучитьСтаршийИдентификатор(строГС);
    пар=Новый Структура;
    пар.Вставить("Имя","ТестБП");
    пар.Вставить("ТипЭлемента",Тип("ЭлементГрафическойСхемыВложенныйБизнесПроцесс"));
    пар.Вставить("Идентификатор",идБП1);
    пар.Вставить("ТекстЗаголовка","Вложенный БП");
    пар.Вставить("ТекстЗаголовкаБП","Нечто внутри!");
    пар.Вставить("КоординатыКонтура",Новый Структура("Лево,Верх,Ширина,Высота",560,290,100,60));
    ДобавитьФигуру(строГС,пар,соотДобавленных);
    
    идВар=ПолучитьСтаршийИдентификатор(строГС);
    мвар=Новый Массив;
    мвар.Добавить(Новый Структура("Идентификатор,ТекстЗаголовка,Куда,НаправлениеКуда","Вариант1","Превосходно!",идСтоп));
    мвар.Добавить(Новый Структура("Идентификатор,ТекстЗаголовка,Куда,НаправлениеКуда","Вариант2","Замечательно!",идБП1));
    пар=Новый Структура;
    пар.Вставить("Имя","ТестВарианта");
    пар.Вставить("ТипЭлемента",Тип("ЭлементГрафическойСхемыВыборВарианта"));
    пар.Вставить("Идентификатор",идВар);
    пар.Вставить("ТекстЗаголовка","Так как, собственно?");
    пар.Вставить("КоординатыКонтура",Новый Структура("Лево,Верх,Ширина,Высота",440,100,140,100));
    пар.Вставить("Варианты",мвар);
    ДобавитьФигуру(строГС,пар,соотДобавленных);
    
    пар=Новый Структура;
    пар.Вставить("Имя","ТестЛинии4");
    пар.Вставить("ТипЭлемента","ЭлементГрафическойСхемыДекоративнаяЛиния");
    пар.Вставить("Идентификатор",ПолучитьСтаршийИдентификатор(строГС));
    пар.Вставить("ТекстЗаголовка","");
    пар.Вставить("Откуда",идОбр);
    пар.Вставить("Куда",идВар);
    пар.Вставить("ВариантОткуда",0);
    пар.Вставить("ДекоративнаяЛиния",Истина);
    пар.Вставить("ПоложениеТекста",ПоложениеТекстаСоединительнойЛинии.ПервыйСегмент);
    пар.Вставить("СтильСтрелкиНачало",СтильСтрелки.Нет);
    пар.Вставить("СтильСтрелкиКонец",СтильСтрелки.Заполненная);
    пар.Вставить("НаправлениеОткуда",ТипСтороныЭлементаГрафическойСхемы.Право);
    пар.Вставить("НаправлениеКуда",ТипСтороныЭлементаГрафическойСхемы.Верх);
    пар.Вставить("КоординатыКонтура",Новый Структура("СерединаГор,СерединаВерт",400,80));
    ДобавитьФигуру(строГС,пар,соотДобавленных);
    
    СоединитьФигурыЛинией(строГС,соотДобавленных,идСтарт,идДействие1,"Вниз");
    СоединитьФигурыЛинией(строГС,соотДобавленных,идДействие1,идУсловие,"Вниз");
    //СоединитьФигурыЛинией(строГС,соотДобавленных,идУсловие,идДействие2,"Влево");
    //СоединитьФигурыЛинией(строГС,соотДобавленных,идУсловие,идСтоп,"Вниз");
    
    ГС=ДесериализоватьГС(строГС);
КонецПроцедуры

Если теги всё-таки побьются, пишите в личку - пришлю исходник как файл.

Кому пригодится - буду рад. Если возникнут пожелания по доработке, тоже отписывайтесь в теме или в личке. А то ведь метода УдалитьФигуру я делать пока не стал, лень-матушка.

 

Графическая схема GRS сериализация xml-структура внутренний формат графической схемы

См. также

Богатый редактор картинок, хранимых в базе, с возможностью РИСОВАНИЯ. Редактор внешних файлов картинок. Объект, расширяющий возможности работы с картинками из встроенного языка (Три в одном) + Обработка «Стандартизация картинок»

Работа с интерфейсом Рабочее место Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Платные (руб)

Обработка предназначена для редактирования картинок в режиме «Предприятие», с возможностью РИСОВАТЬ на них. Поддерживается работа как в обычных формах (толстый клиент) так и на управляемых формах (тонкий клиент). Обработка позволяет редактировать как картинки, хранимые в базе, так и графические файлы с диска на файловой системе. Помимо базовых функций (изменение размеров, преобразование формата, обрезание картинки, повороты и т.п.) – редактор имеет богатый набор инструментов для рисования. Доступна функция вставки изображения из буфера обмена. Также обработка может быть использована из встроенного языка как объект для редактирования картинок. Объект может быть использован: на стороне клиента, на стороне сервера, из внешнего соединения. Данная обработка будет особенно полезна тем, кто вносит картинки в базу (изображения номенклатуры, фотографии физических лиц и т.п.). Функционал реализуется с использованием JavaScript и бесплатного ПО ImageMagick (без использования внешних компонент).

6000 руб.

16.01.2015    61797    43    59    

80

[Расширения] Динамическое управление видимостью и доступностью элементов форм (УФ) (8.3.6+)

Работа с интерфейсом Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Платные (руб)

Механизм «Динамическое управление доступом к элементам форм объектов 1С8» предназначен для обеспечения возможности оперативного управления видимостью и доступностью элементов форм документов и справочников продуктов фирмы «1С» «1С:Предприятие 8». Решение универсальное, встраивается в любую конфигурацию с минимальными доработками, что позволяет без проблем обновлять типовые решения.

5000 руб.

14.01.2016    54403    16    21    

42

Управление дашбордами

Работа с интерфейсом Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

Обработка предназначена для создания и управления дашбордами.

2400 руб.

29.06.2020    16698    21    4    

35

Новогоднее оформление для 1С

Работа с интерфейсом Платформа 1С v8.3 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Зарплата и Управление Персоналом 3.x 1С:Управление нашей фирмой 3.0 Бесплатно (free)

Добавьте новогоднего настроения! Расширение создает декорацию в виде гирлянды на некоторых формах объектов.

27.12.2023    10738    750    elcoan    45    

106

Конструктор HTML, CSS и javascript

Инструментарий разработчика Работа с интерфейсом Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Подходит для создания web-страниц для замены управляемых форм 1С, красивых отчетов, интерфейса мобильного приложения на платформе 1С и для простых страниц веб-сайтов.

2 стартмани

10.04.2023    9617    151    acces969    31    

118

Модель состояния для MVC

Работа с интерфейсом Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

"MVC плохо применима в 1С" - познакомьтесь с моделью состояния и, возможно, ваше мнение поменяется! Представленное решение является эволюционным развитием идеи реализации MVC для 1С. В новой версии добавлены DSL для описания модели состояния, а также параметризация свойств параметров и элементов формы.

1 стартмани

05.07.2022    3666    kalyaka    2    

27

Табло очереди заказов на экран телевизора

WEB-интеграция Работа с интерфейсом Платформа 1С v8.3 1С:Розница 2 Платные (руб)

Связка из веб-приложения и расширения для 1С: Розница 2.3.

3600 руб.

29.04.2022    12082    1    5    

10
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. Alias 176 19.07.16 16:54 Сейчас в теме
Тэги не побились, всё работает.
Вернее, почти всё... в случае если региональные установки разделителя целой и дробной является запятая (Россия), в XML попадают числа типа 191,5 (с запятой), что делает результирующую XML-строку некорректной. Дроби получились от деления на 2 (когда ищем середину).
Заменил Строка() на XMLСтрока() в функции ДобавитьКоординатыФигуры(), после чего стало совсем замечательно.

P.S. Линии декоративные вместо нормально-привязанных (например, от выбора варианта), это недоработка или особенность?
2. Yashazz 4709 19.07.16 19:28 Сейчас в теме
(1) Alias, блин, насчёт декоративных линий - это я в итоге мучений с публикацией не ту версию скопипастил. Конечно, там должны быть привязываемые. Это рулится параметром "ДекоративнаяЛиния". Извиняюсь. А вот насчёт формата - тупо прохлопал. Постараюсь обновить публикацию, спасибо.
Atori-kun; +1 Ответить
3. vandalsvq 1537 19.07.16 22:55 Сейчас в теме
(2) прикрепи обработку, у кого мани есть могут скачать. Все лучше чем со статьи копипастить ))))
4. Сурикат 393 20.07.16 08:44 Сейчас в теме
Огромное спасибо за публикацию!
5. Yashazz 4709 20.07.16 09:28 Сейчас в теме
Коллеги-товарищи, я собираюсь эту штуку развивать дальше, поэтому очень приветствуется критика. Где-какие косяки и недоработки, пишите.
6. konstruktiv 20.07.16 13:59 Сейчас в теме
(5) тоже делал такое, также использовал XDTO-сериализацию. В своем время разобрался со многими вещами, даже которые нельзя было сделать интерактивно (перевернуть фигуру на 75 градусов, фон заштриховать). Бросил это дело из-за одной мелочи, поэтому хочу сразу предостеречь. Но возможно я просто не нашел решения.
1. Получается, что стрелки можно сделать только параллельно осям с изгибом только в 90 градусов. Тут вроде бы не страшно. Не так уж плохо и выглядит.
2. Когда связываешь стрелку с фигурой - то есть при интерактивном перетаскивании фигуры стрелка не отклеивается - так вот стрелка может примыкать только к одному из 4 секторов, только к одной точке. А это уже порождает ограничения.
Например разными стрелками будем обозначать товар, деньги и т.п. Соответственно из-за описанных выше ограничений стрелки разного вида сольются в одну. Можно сделать чтобы при первом формировании они не склеивались, но как только передвинешь что-то мышкой, они склеиваются. А интерактивность все-таки лучше оставить в таком продукте.
8. Yashazz 4709 20.07.16 14:35 Сейчас в теме
(6) Ага, копаю в эту сторону.
Кстати, в процессе изучения выяснилось, что рисовать можно ЛЮБЫЕ фигуры. Любой формы. Если задать координаты, так получаются жуткие звёзды, кривые косоугольники и прочая прелесть. Ну и декорации со всякими овалами тоже))) Тут да, простор для творчества. Правда, надпись при этом может отказаться не внутри многоугольника, а где-то вообще мимо.

(7) Справедливости ради, я где-то в планах 1С видел программное изменение коллекций фигур схемы, но под таким пятизначным приоритетом, что ещё год-полтора ждать точно...
9. konstruktiv 20.07.16 15:19 Сейчас в теме
(8) про любые фигуры тоже проходили)) вроде скрытых возможностей дофига, но как только пытаешься приложить к какой-нибудь реальной задаче, так руки опускаются
7. konstruktiv 20.07.16 14:03 Сейчас в теме
(5) с этими ключами тоже разобрался:
<printPropItem><key>6</key><val>10</val></printPropItem>
|<printPropItem><key>7</key><val>10</val></printPropItem>
|<printPropItem><key>8</key><val>10</val></printPropItem>
|<printPropItem><key>9</key><val>10</val></printPropItem>
|<printPropItem><key>13</key><val>0</val></printPropItem>
|<printPropItem><key>16</key><val>0</val></printPropItem>
Я не скачивал обработку, но я использовал только сериализованные объекты, которые дает платформа, сам текст XML не парсил и не собирал.
А вообще ощущение, что сами 1сники забросили этот объект, а жаль...
10. Nikola23 696 21.07.16 09:08 Сейчас в теме
(5) Зачем тратить силы на собирание строк XML вручную, если то же самое прекрасно работает с использованием XDTO? Объектная модель рулит.
Чем принципиально эта публикация отличается от еще нескольких подобных? Много кода, но зачем?
11. Yashazz 4709 21.07.16 15:45 Сейчас в теме
(10) Nikola23, покажите мне эти подобные, пожалуйста. Кроме работы Diversus'а, конечно. И объясните насчёт XDTO - вы предлагаете оперировать абстракциями на уровне элементов схемы? Ну, можно и так, конечно, только вот у меня несколько попыток подобного подхода обламывались - схема не собиралась обратно.

Чем ещё отличается - полной доступностью. Можно воспользоваться безо всяких стартманей.
12. Nikola23 696 27.07.16 00:53 Сейчас в теме
(11) Никаких хитрых абстракций.
Предлагаю возможность настраивать свойства (в т..ч. методом тыка) с использованием привычной объектной модели.
Если задача сводится к нарисовать - то Ваш метод может и подойдет, а если необходимо проанализировать структуру связей схемы и построить по нарисованной картинке автоматизацию?
Если не нашли решения на инфостарте, это значит, либо плохо искали, либо оно куда-то делось.
Я пользуюсь наработками скачанными отсюда.
13. Yashazz 4709 27.07.16 17:44 Сейчас в теме
(12) Nikola23, а, так это я тоже практикую. В публикации http://infostart.ru/public/531533/ я именно так и поступил - создал только самое необходимое, дальше донастроил штатными методами и свойствами языка.
А вот за отсутствие пруфлинка и при этом фразу "плохо искали" - мой вам респект, ибо отсутствие ссылки значит, что аналогов у моей публикации всё-таки нету)))
14. user595212_go.blin2014 25.08.16 22:39 Сейчас в теме
Ценная статья, благодарю.
16. Yashazz 4709 08.09.16 09:55 Сейчас в теме
(15) DrAku1a, да, я указал её как первоисточник. Я от этой идеи собственно и отталкивался. Ещё раз Diversus'у спасибо.
Правда, там в комментах один товарищ указывает, что это всё было изобретено ещё раньше. Что, в общем, не удивительно)
21. RainyAugust22 265 29.12.16 07:26 Сейчас в теме
Где можно скачать в виде обработки?
Скопипастил код в обработку, не получается запустить, помогите плз:
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(16)}: Ошибка при вызове метода контекста (ПрочитатьXML)
Возврат СериализаторXDTO.ПрочитатьXML(чтен,Тип("ГрафическаяСхема"));
по причине:
Ошибка преобразования данных XDTO:
НачалоСвойства: {http://v8.1c.ru/8.2/data/graphscheme}FlowchartContextType Форма: Элемент Тип: {http://v8.1c.ru/8.2/data/graphscheme}FlowchartContextType
по причине:
Ошибка преобразования данных XDTO:
Значение: 191,5 Тип: {http://www.w3.org/2001/XMLSchema}decimal
по причине:
Ошибка отображения типов:
Отображение типа '{http://www.w3.org/2001/XMLSchema}decimal' в тип 'Число'
22. Yashazz 4709 29.12.16 12:15 Сейчас в теме
(21) Ух, красота... Какая у Вас платформа 1С?
23. RainyAugust22 265 29.12.16 15:41 Сейчас в теме
24. Yashazz 4709 29.12.16 20:46 Сейчас в теме
(23) Так это, думаю, просто релиз кривой. 1С, как всегда, косячат неимоверно. Попробуйте на чём-то надёжном вроде 8.3.6
17. serg_infostart 386 22.09.16 16:38 Сейчас в теме
Нужен жесткий контроль за itemid, нельзя допускать повторения - иначе будут глюки (срывается соединение между элементами при любой подвижке элемента).
В вышеуказанном блоке изменить:
				// добавляем линию с координатой, начинающейся от середины варианта
				//парПолучателяЛинии=соотДобавленных.Получить(рВариант.Куда); - если надо получитьэти данные
				парЛВ=Новый Структура;
				парЛВ.Вставить("Имя","ЛинияВарианта"+рВариант.Идентификатор);
				парЛВ.Вставить("ТипЭлемента","ЭлементГрафическойСхемыДекоративнаяЛиния");
				парЛВ.Вставить("Идентификатор",ПолучитьСтаршийИдентификатор(строГС));

на:
				// добавляем линию с координатой, начинающейся от середины варианта
				//парПолучателяЛинии=соотДобавленных.Получить(рВариант.Куда); - если надо получитьэти данные
				парЛВ=Новый Структура;
				парЛВ.Вставить("Имя","ЛинияВарианта"+рВариант.Идентификатор);
				парЛВ.Вставить("ТипЭлемента","ЭлементГрафическойСхемыДекоративнаяЛиния");
				парЛВ.Вставить("Идентификатор",пар.Идентификатор + й + 1); // Вот тут нужно изменить - иначе добавляет существующие itemid 

В остальном, все хорошо.
Напрашивается оптимизация кода, возможно через использование ФабрикиXDTO. И выпустить в виде отдельного серверного модуля.
Я же хочу на вход подавать простейшую структуру взаимосвязей, на выходе получать ГрафическуюСхему - как раз в процессе производства.
И конечно же благодаря статье сэкономлена куча времени. Автору и предшественникам благодарность.
18. serg_infostart 386 22.09.16 17:01 Сейчас в теме
Да, еще нюанс.
Системные перечисления сторон (portIndex):
1: Лево
2: Верх
3: Право
4: Низ
5: Центр
6: Вариант 1 Лево
7: Вариант 1 Право
8: Вариант 2 Лево
9: Вариант 2 Право
10: ..... и т.д.

Поэтому, придется исправить еще и порт источника для Декоративной линии варианта.
Кусок кода
				парЛВ.Вставить("НаправлениеОткуда",ТипСтороныЭлементаГрафическойСхемы.Право); // всегда

меняем на
				парЛВ.Вставить("НаправлениеОткуда",7+й*2); // всегда
19. serg_infostart 386 22.09.16 17:09 Сейчас в теме
Не обязательно, т.к. работает и без этого, но...
Для чистоты преобразований заменим
парЛВ.Вставить("ВариантОткуда",0);
заменить на
парЛВ.Вставить("ВариантОткуда",й);
20. serg_infostart 386 27.09.16 15:29 Сейчас в теме
Сделал объектную модель. Ссылка на эту статью имеется - без этой статьи не решился бы создать свой вариант реализации.
http://infostart.ru/public/551576/ (скоро будет доступна).
25. Valeric650 20.07.21 15:40 Сейчас в теме
Спасибо за статью. Воспользовался вашим способом. Но есть проблема, т.к. соединяющие линии не обходят элементы схемы и рисуются напрямую через блоки. Есть способ решения данной проблемы (оч нужно)?
(в примере связующая линия блок 1 -> блок 3 пересекает блок 2)
Прикрепленные файлы:
26. Yashazz 4709 20.07.21 15:52 Сейчас в теме
(25) Тип линии - декоративная или настоящая соединительная? Так вроде декоративки без чёткой привязки себя ведут. Ну или попробуйте задавать середины линий, чтоб априорно сдвинуть куда-нибудь наверняка мимо.
28. Valeric650 20.07.21 16:18 Сейчас в теме
(26) Задавать середины линии (в т.ч. со смещением) тоже положительного результата не даёт. Схема может получиться сложная, основная фишка графической схемы это автоматическая прокладка линий, рисовать их вручную - не вариант.
HELP
29. Yashazz 4709 20.07.21 18:35 Сейчас в теме
(28) Самое обидное, что у меня был такой вариант, и как-то довольно просто он решался, свойство что ли какое-то... Вот убей, не помню ((
Причём там именно автопрокладка срабатывала, и верно срабатывала... Попробуйте сделать такую линию вручную, чтоб автоматом обошла фигуру, и сравните её свойства со свойствами сделанной программно.
30. Valeric650 21.07.21 08:19 Сейчас в теме
(29) Пробовал, вся разница только в новых координатах линии, больше ничего.
Если вдруг вспомнишь как решил этот вопрос, дай знать пожалуйста.
27. Valeric650 20.07.21 16:02 Сейчас в теме
Линии пробовал и декароктивные и соединяющие, на результат не влияет.
Оставьте свое сообщение