Программная работа с графическими схемами. Готовое решение

Публикация № 787780

Разработка - Инструментарий разработчика

Графическая схема; Программное изменение графической схемы; Построение графической схемы

Работоспособное, проверенное на практике, простое и удобное программное управление графическими схемами.

После множества публикаций, где идея была продемонстрирована, развита и обсуждена, мне по работе довелось-таки создать полноценное решение и погонять его всерьёз. Останавливаться на подробностях самой идеи не буду, она высказана много где (начиная с //catalog.mista.ru/public/320691/ и заканчивая моей предыдущей). Концепцию взял у //catalog.mista.ru/public/551576/ и допилил под свой извращённый вкус. Здесь просто выкладываю работающий исходник и обработку, позволяющую всё это эксплуатировать уже на уровне шаблона решения. То есть, можно взять обработку и довольно легко "допилить" под свои нужды. Собственно, она и делалась для себя любимого как универсал)

Обработка предусматривает просмотр, построение, изменение схем согласно любым исходным данным. Там есть специальные шлюзы-интерфейсы, куда можно подключить собственную конкретную механику. Я не стал особенно заморачиваться красотой расположения фигур на схеме - желающие могут почитать теорию графов сами или адаптировать публикацию Ильдаровича, я сделал лишь "квадратно-гнездовое" расположение (с возможностью группировки фигур в блоки или без) и "типа-древовидное", с распихиванием фигур по уровням сначала по длине пути к ним в графе, а потом по незанятым областям.

Фигуры размещаются каждая в свою "зону", линии отрисовываются автоматом. Можно показывать одиночные фигуры. Можно обрабатывать события схемы и её элементов. Для графов со многими исходящими есть варианты показа. Есть удобные визуальные прибамбасы. Форма работает в режиме просмотра и правки схемы.

Также в коде обработки предусмотрен вызов при открытии; есть механизмы работы с таблицей вершин, таблицей рёбер, матрицей переходов - кому что окажется удобнее. Ещё есть механизм отслеживания изменений и их индикации, сравнения данных из БД с данными из самой схемы, схема умеет записываться с сохранением всех внутренних данных и восстанавливаться из ранее записанного. Обработка на УФ для несинхрона.

Часть работы идёт в технике управления xml-json, часть уже в объектной технике графической схемы.

Код снабжён пояснениями, поэтому тут особенно много расписывать не буду. Если у кого возникнут вопросы - постараюсь в теме более подробно рассказать, т.к. заранее вообще не представляю, кого что заинтересует.

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

У формы обработки есть встроенная справка, правда, в основном с точки зрения пользователя, но основные фишки там описаны.

Ещё раз подчеркну, что "готовым решением" является в первую очередь код управления схемой, а обработка - это шаблон, заготовка без заточки под конкретные нужды.

 

Пример вызова (а вообще их много в обработке):        

рИмяФигуры="Фигура1";
        рТипЭлемента=Тип("ЭлементГрафическойСхемыДействие");
        рСхема=Обработки.РаботаСГрафическойСхемой.ИнициализироватьСхему();
        
        эгсФигура=Обработки.РаботаСГрафическойСхемой.ИнициализироватьЭлементСхемы(рСхема,рТипЭлемента,рИмяФигуры);
        Если эгсФигура=Неопределено Тогда Возврат КонецЕсли;
        //эгсФигура.Вставить("explanation",рИмяФигуры);
        //
        рКоординаты=Новый Структура;
        рКоординаты.Вставить("Лево",40);
        рКоординаты.Вставить("Верх",40);
        рКоординаты.Вставить("Ширина",300);
        рКоординаты.Вставить("Высота",100);
        Обработки.РаботаСГрафическойСхемой.УстановитьКоординатыЭлементаСхемы(эгсФигура,рКоординаты);
        //
        Обработки.РаботаСГрафическойСхемой.УстановитьЗаголовокЭлементаСхемы(эгсФигура,"Некий заголовок");
        //
        идФигуры=Обработки.РаботаСГрафическойСхемой.ДобавитьЭлементВСхему(рСхема,эгсФигура);
        Если не ЗначениеЗаполнено(идФигуры) Тогда Возврат КонецЕсли;
        
        Если выбзнч.Значение<>Тип("ЭлементГрафическойСхемыДекорация") Тогда
            рИмяЛинии="Линия1";
            эгсЛиния=Обработки.РаботаСГрафическойСхемой.ИнициализироватьЭлементСхемы(рСхема,Тип("ЭлементГрафическойСхемыСоединительнаяЛиния"),рИмяЛинии);
            //
            рПараметры=Новый Структура("Схема",рСхема);
            рПараметры.Вставить("Начало",идФигуры);
            //рПараметры.Вставить("Конец",0); // стрелка не ведёт никуда
            рПараметры.Вставить("НачалоСторона",ТипСтороныЭлементаГрафическойСхемы.Низ);
            Обработки.РаботаСГрафическойСхемой.УстановитьКоординатыЭлементаСхемы(эгсЛиния,рПараметры);
            //
            идЛинии=Обработки.РаботаСГрафическойСхемой.ДобавитьЭлементВСхему(рСхема,эгсЛиния);
            //Если не ЗначениеЗаполнено(идЛинии) Тогда            
        КонецЕсли;
        
        гс=Обработки.РаботаСГрафическойСхемой.СобратьГрафическуюСхему(рСхема);


Собственно код самой главной исполняемой части:

#Область УправлениеГрафическойСхемой

#Область ОбщееСлужебное

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

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

// Используется в первичной и вторичной механике для определения, чем будет коллекция - структурой или соответствием. По умолчанию структура.
Функция НовыйСоответствиеСтруктура()
    Возврат Новый Структура;
КонецФункции

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

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


#Область ДействияПервичногоПостроения

// Действия первичного построения необходимы для построения схемы на основе атомарных данных, компонуют коллекцию коллекций свойств объектов схемы,
// которая затем будет через JSON преобразована в строку и десериализована в объект "ГрафическаяСхема".
// Рекомендуется ИнициализироватьСхему, затем создать нужные элементы, используя ИнициализироватьЭлементСхемы, УстановитьКоординатыЭлементаСхемы
// и УстановитьЗаголовокЭлементаСхемы, затем СобратьГрафическуюСхему.
// Обычно при первичном построении большинство коллекций это структуры, а не соответствия.
// Важно! ИнициализироватьСхему это единственная функция, которая применима только на начальном этапе, т.к. работает всегда со структурой, а не соответствием.

// Возвращает соответствие с одним элементом #value, типа Структура; состав структуры аналогичен сериализованным свойствам графической схемы.
// При ошибке возвращает Неопределено.
//
// Параметры:
//    рПараметры - структура, описывающая настройки схемы; необязательный, если не указан, схема создаётся с настройками по умолчанию;
//    параметры можно заполнять из данных уже имеющейся ГС с помощью ЗаполнитьЗначенияСвойств.
//    Ключи структуры:
//        ИспользоватьСетку (булево), по умолчанию Истина;
//        РежимОтрисовкиСетки (свойство ГС), по умолчанию Линии;
//        ГоризонтальныйШагСетки (число), по умолчанию 20;
//        ВертикальныйШагСетки (число), по умолчанию 20.
//
Функция ИнициализироватьСхему(рПараметры=Неопределено) Экспорт
Попытка
    Если ТипЗнч(рПараметры)<>Тип("Структура") Тогда рПараметры=Новый Структура КонецЕсли;
    
    рИспользоватьСетку=?(рПараметры.Свойство("ИспользоватьСетку"),рПараметры.ИспользоватьСетку,Истина);
    рРежимОтрисовкиСетки=?(рПараметры.Свойство("РежимОтрисовкиСетки"),рПараметры.РежимОтрисовкиСетки,РежимОтрисовкиСеткиГрафическойСхемы.Линии);
    рГоризонтальныйШагСетки=?(рПараметры.Свойство("ГоризонтальныйШагСетки"),рПараметры.ГоризонтальныйШагСетки,20);
    рВертикальныйШагСетки=?(рПараметры.Свойство("ВертикальныйШагСетки"),рПараметры.ВертикальныйШагСетки,20);
    //
    Если рИспользоватьСетку Тогда
        Если рРежимОтрисовкиСетки=РежимОтрисовкиСеткиГрафическойСхемы.Линии Тогда
            рОтрисовка="Lines";
        ИначеЕсли рРежимОтрисовкиСетки=РежимОтрисовкиСеткиГрафическойСхемы.Точки Тогда
            рОтрисовка="Dots";
        ИначеЕсли рРежимОтрисовкиСетки=РежимОтрисовкиСеткиГрафическойСхемы.ШахматнаяСетка Тогда
            рОтрисовка="Chess";
        Иначе
            рОтрисовка="None";
        КонецЕсли;
    Иначе
        рОтрисовка="None";
    КонецЕсли;    
    
    струСхема=Новый Структура;
    струСхема.Вставить("backColor", Новый Соответствие);
    струСхема.backColor.Вставить("#type", "jv8ui:Color");
    струСхема.backColor.Вставить("#value", "{http://v8.1c.ru/8.1/data/ui/style}FieldBackColor");
    струСхема.Вставить("enableGrid",рИспользоватьСетку);
    струСхема.Вставить("drawGridMode",рОтрисовка);
    струСхема.Вставить("gridHorizontalStep",рГоризонтальныйШагСетки);
    струСхема.Вставить("gridVerticalStep",рВертикальныйШагСетки);
    струСхема.Вставить("bpUUID", "00000000-0000-0000-0000-000000000000");
    струСхема.Вставить("useOutput", "Auto");
    струСхема.Вставить("printPropItem", Новый Массив);
    струСхема.printPropItem.Добавить(Новый Структура("key,val",6,10    ));
    струСхема.printPropItem.Добавить(Новый Структура("key,val",7,10    ));
    струСхема.printPropItem.Добавить(Новый Структура("key,val",8,10    ));
    струСхема.printPropItem.Добавить(Новый Структура("key,val",9,10    ));
    струСхема.printPropItem.Добавить(Новый Структура("key,val",13,0    ));
    струСхема.printPropItem.Добавить(Новый Структура("key,val",16,0    ));
    
    //струСхема.Вставить("item", Новый Массив); // добавлять только если есть хотя бы один элемент
    
    рСтруктурыТиповЭлементовГС=ПостроитьКэшСтруктурВсехТиповЭлементовСхемы(); // для элементов этой схемы
    
    значСхема=Новый Соответствие;
    значСхема.Вставить("#value",струСхема);
    значСхема.Вставить("СтруктурыТиповЭлементов",рСтруктурыТиповЭлементовГС);
    Возврат значСхема;
    
Исключение
    Сообщить("ИнициализироватьСхему, общая ошибка: "+ОписаниеОшибки());
    Возврат Неопределено;
КонецПопытки;
КонецФункции

// Возвращает массив строковых кратких названий элементов ГС.
//
Функция ПостроитьНотациюТиповЭлементовСхемы()
    спТиповЭлементовГС=Новый СписокЗначений;
    спТиповЭлементовГС.Добавить(0,"Декорация");
    //спТиповЭлементовГС.Добавить(1,"ДекоративнаяЛиния"); // потом продумать вопрос, когда по коду определяется тип - неоднозначная ситуация!
    спТиповЭлементовГС.Добавить(1,"СоединительнаяЛиния");
    спТиповЭлементовГС.Добавить(2,"Старт");
    спТиповЭлементовГС.Добавить(3,"Завершение");
    спТиповЭлементовГС.Добавить(4,"Условие");
    спТиповЭлементовГС.Добавить(5,"Действие");
    спТиповЭлементовГС.Добавить(6,"ВыборВарианта");
    спТиповЭлементовГС.Добавить(7,"Разделение");
    спТиповЭлементовГС.Добавить(8,"Слияние");
    спТиповЭлементовГС.Добавить(9,"Обработка");
    спТиповЭлементовГС.Добавить(10,"ВложенныйБизнесПроцесс");
    Возврат спТиповЭлементовГС;
КонецФункции

// Возвращает число, соотвтетствующее типу стороны элемента ГС.
// При отсутствии подходящих значений или при ошибке возвращает Неопределено.
//
// Параметры:
//    рТип - значение типа ТипСтороныЭлементаГрафическойСхемы, если задание стороны делается для любого элемента ГС, кроме Выбора,
//        или структура с обязательными ключами ТипСтороны и НомерВарианта, если задание стороны делается для варианта элемента Выбор.
//
Функция ПреобразоватьТипСтороныЭлементаВЧисло(рТипИлиВариант)
Попытка
    // Кроме основных 1-5, используются стороны вариантов (только для элемента ВыборВарианта):
    //// чётные - левые стороны, нечётные - правые
    //// поэтому 1 вариант левая сторона - это 6, а 1 вариант правая сторона - 7
    //// для 2 варианта: 8 (лево) и 9 (право) соответственно
    Если ТипЗнч(рТипИлиВариант)=Тип("Структура") Тогда
        // это указание на вариант выбора
        Если рТипИлиВариант.ТипСтороны=ТипСтороныЭлементаГрафическойСхемы.Лево Тогда
            коэф=0;
        ИначеЕсли рТипИлиВариант.ТипСтороны=ТипСтороныЭлементаГрафическойСхемы.Право Тогда
            коэф=1;
        Иначе
            Возврат Неопределено;
        КонецЕсли;
        Возврат 2*(3+рТипИлиВариант.НомерВарианта)+коэф;
    Иначе
        Если рТипИлиВариант=ТипСтороныЭлементаГрафическойСхемы.Лево Тогда Возврат 1
        ИначеЕсли рТипИлиВариант=ТипСтороныЭлементаГрафическойСхемы.Верх Тогда Возврат 2
        ИначеЕсли рТипИлиВариант=ТипСтороныЭлементаГрафическойСхемы.Право Тогда Возврат 3
        ИначеЕсли рТипИлиВариант=ТипСтороныЭлементаГрафическойСхемы.Низ Тогда Возврат 4
        ИначеЕсли рТипИлиВариант=ТипСтороныЭлементаГрафическойСхемы.Центр Тогда Возврат 5
        Иначе Возврат Неопределено;        
        КонецЕсли;
    КонецЕсли;    
Исключение
    Сообщить("ПреобразоватьТипСтороныЭлементаВЧисло, общая ошибка: "+ОписаниеОшибки());
    Возврат Неопределено;
КонецПопытки;
КонецФункции

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

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

    струЭлемента=Новый Структура; // здесь это может быть структурой; потом оно при необходимости преобразуется в соответствие
    
    струЭлемента.Вставить("itemType",                рКодТипаЭлемента);
    
    струЭлемента.Вставить("lineColor",                Новый Соответствие);
    струЭлемента.lineColor.Вставить("#type",        "jv8ui:Color");    
    струЭлемента.lineColor.Вставить("#value",        "{http://v8.1c.ru/8.1/data/ui/style}BorderColor");
    //
    струЭлемента.Вставить("backColor",                Новый Соответствие);
    струЭлемента.backColor.Вставить("#type",        "jv8ui:Color");
    струЭлемента.backColor.Вставить("#value",        "auto");
    //
    струЭлемента.Вставить("textColor",                Новый Соответствие);
    струЭлемента.textColor.Вставить("#type",        "jv8ui:Color");
    струЭлемента.textColor.Вставить("#value",        "{http://v8.1c.ru/8.1/data/ui/style}FormTextColor");
    
    струЭлемента.Вставить("alignHor",                "Center");
    струЭлемента.Вставить("alignVer",                "Center");
    струЭлемента.Вставить("currentLanguage",        "#");
    струЭлемента.Вставить("picturePlacement",        "Left");
    струЭлемента.Вставить("textFont",                Новый Структура("kind","AutoFont"));
    струЭлемента.Вставить("tipText",                Новый Соответствие);
    струЭлемента.Вставить("transparent",            Ложь);
    струЭлемента.Вставить("hyperlink",                Ложь);
    струЭлемента.Вставить("itemTitle",                Новый Массив);
    струЭлемента.Вставить("groupNum",                0);
    
    
    Если рКодТипаЭлемента=0 Тогда
        струЭлемента.Вставить("angle",                    Новый Соответствие);
        струЭлемента.angle.Вставить("#type",    "jxs:decimal");
        струЭлемента.angle.Вставить("#value",    0);
        струЭлемента.Вставить("flipMode",                0);
        струЭлемента.Вставить("shape",                    "Block");
    Иначе
        струЭлемента.Вставить("border",                Новый Структура("width,gap,style",Новый Соответствие,Ложь,Новый Соответствие));
        струЭлемента.border.width.Вставить("#type",    "jxs:decimal");
        струЭлемента.border.width.Вставить("#value",    1);
        струЭлемента.border.style.Вставить("#type",    "jsch:ConnectorLineType");
        струЭлемента.border.style.Вставить("#value",    "Solid");
        струЭлемента.Вставить("point",                    Новый Массив);
    КонецЕсли;
    
    Если рКодТипаЭлемента=1 Тогда
        струЭлемента.Вставить("beginArrowStyle",        "None");
        струЭлемента.Вставить("connectFromItemId",        -1); // Если decorativeLine=Истина, то можно и из ниоткуда
        струЭлемента.Вставить("connectFromPortIndex",    0);
        струЭлемента.Вставить("connectToItemId",        -1);
        струЭлемента.Вставить("decorativeLine",        Истина); // Если Ложь, то будет неубираемая "пристегнутая" линия к объекту
        струЭлемента.Вставить("endArrowStyle",            "Filled");
        струЭлемента.Вставить("portIndexFrom",            4);
        струЭлемента.Вставить("portIndexTo",            0);
        струЭлемента.Вставить("textPos",                "FirstSegment");
    Иначе
        струЭлемента.Вставить("rectBottom",            40);
        струЭлемента.Вставить("rectLeft",                60);
        струЭлемента.Вставить("rectRight",                80);
        струЭлемента.Вставить("rectTop",                20);
        струЭлемента.Вставить("picture",                Новый Соответствие);
        струЭлемента.Вставить("pictureStyle",            4);
    КонецЕсли;
    
    Если рКодТипаЭлемента >= 2 Тогда
        струЭлемента.Вставить("pointUUID",                Строка(Новый УникальныйИдентификатор));
        струЭлемента.Вставить("passageState",            0);
        струЭлемента.Вставить("tableCode",                0);
    КонецЕсли;
    
    Если рКодТипаЭлемента=4 Тогда
        струЭлемента.Вставить("falsePortIndex",        1);
        струЭлемента.Вставить("truePortIndex",            3);
    ИначеЕсли рКодТипаЭлемента=5 Тогда
        струЭлемента.Вставить("addrZoneDivideYPos",    16);
        струЭлемента.Вставить("groupAddressing",        Ложь);
        струЭлемента.Вставить("isAddrZoneDivideValid",    Истина);
        струЭлемента.Вставить("explanation",            "");
    ИначеЕсли рКодТипаЭлемента=6 Тогда
        струЭлемента.Вставить("transition",            Новый Массив);
    ИначеЕсли рКодТипаЭлемента=10 Тогда
        струЭлемента.Вставить("subprocessUUID",        "00000000-0000-0000-0000-000000000000");
    КонецЕсли;
    
    Возврат струЭлемента;
    
Исключение
    Сообщить("ПостроитьСтруктуруДляТипаЭлементаСхемы, общая ошибка: "+ОписаниеОшибки(),СтатусСообщения.Важное);
    Возврат Неопределено;
КонецПопытки;
КонецФункции

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

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

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

// Расставляет все точки, нужные для отрисовки элемента ГС, согласно указанным координатам, определяя прямоугольную область "обитания" элемента ГС и его фигуру.
//
// Параметры:
//    струЭлемента - структура/соответствие, соответствующая типу элемента (определяемая ранее в ПостроитьСтруктуруДляТипаЭлементаСхемы);
//    рПараметры - структура, где:
//        для не-линий обязательны числовые: ключи Лево, Верх, Ширина, Высота;
//        для линий обязательны ключи: Схема (структура), Начало и Конец (структуры или id); и необязательны ДекоративнаяЛиния (булево),
//        НачалоСторона и КонецСторона (типа ТипСтороныЭлементаГрафическойСхемы).
//        При этом, если нужно, чтобы стрелка никуда не вела, следует НЕ указывать вообще ключ "Конец".
//
Процедура УстановитьКоординатыЭлементаСхемы(струЭлемента,рПараметры=Неопределено) Экспорт
Попытка
    рТипЭлемента=СоотСвойство(струЭлемента,"Тип");
    //
    Если рТипЭлемента=Тип("ЭлементГрафическойСхемыДекоративнаяЛиния") 
    или рТипЭлемента=Тип("ЭлементГрафическойСхемыСоединительнаяЛиния") 
    Тогда    
        рНачало=?(ТипЗнч(рПараметры.Начало)=Тип("Структура"),рПараметры.Начало.ItemId,рПараметры.Начало);
        Если рПараметры.Свойство("Конец") Тогда
            рКонец=?(ТипЗнч(рПараметры.Конец)=Тип("Структура"),рПараметры.Конец.ItemId,рПараметры.Конец);
        Иначе
            // линия никуда не ведёт
            рКонец=0;
        КонецЕсли;        
        //
        струЭлемента.Вставить("decorativeLine",?(рПараметры.Свойство("ДекоративнаяЛиния"),рПараметры.ДекоративнаяЛиния,Ложь));
        струЭлемента.Вставить("connectFromItemId",рНачало);
        струЭлемента.Вставить("connectToItemId",рКонец);
        //
        рТипСтороныНач=?(рПараметры.Свойство("НачалоСторона"),ПреобразоватьТипСтороныЭлементаВЧисло(рПараметры.НачалоСторона),Неопределено);
        рТипСтороныНач=?(рТипСтороныНач=Неопределено,1,рТипСтороныНач); // лево
        струЭлемента.Вставить("portIndexFrom",рТипСтороныНач);
        //
        рТипСтороныКон=?(рПараметры.Свойство("КонецСторона"),ПреобразоватьТипСтороныЭлементаВЧисло(рПараметры.КонецСторона),Неопределено);
        Если рКонец<>0 Тогда
            рТипСтороныКон=?(рТипСтороныКон=Неопределено,2,рТипСтороныКон); // верх
            струЭлемента.Вставить("portIndexTo",рТипСтороныКон);
        КонецЕсли;
        
        рПортВарианта=СоотСвойство(струЭлемента,"connectFromPortIndex");
        //
        // Рисуем только начало и окончание. Остальное система дополнит сама при отрисовке.        
        рКоординатыНач=РассчитатьКоординатыЭлемента(рПараметры.Схема,рНачало,рТипСтороныНач,рПортВарианта);
        Если рКонец<>0 Тогда
            рКоординатыКон=РассчитатьКоординатыЭлемента(рПараметры.Схема,рКонец,рТипСтороныКон);
            Если рКоординатыНач=Неопределено или рКоординатыКон=Неопределено Тогда
                Сообщить("УстановитьКоординатыЭлементаСхемы, ошибка расчёта координат элемента "+СокрЛП(струЭлемента.Имя)+"!");
                Возврат;
            КонецЕсли;
        КонецЕсли;
        //
        струЭлемента.Вставить("connectFromPortIndex",рПортВарианта);
        
        мКоординат=СоотСвойство(струЭлемента,"point");
        Если ТипЗнч(мКоординат)<>Тип("Массив") Тогда мКоординат=Новый Массив КонецЕсли;
        соотНач=НовыйСоответствиеСтруктура();
        соотНач.Вставить("x",рКоординатыНач.x);
        соотНач.Вставить("y",рКоординатыНач.y);
        мКоординат.Добавить(соотНач);
        Если рКонец<>0 Тогда
            соотКон=НовыйСоответствиеСтруктура();
            соотКон.Вставить("x",рКоординатыКон.x);
            соотКон.Вставить("y",рКоординатыКон.y);
            мКоординат.Добавить(соотКон);
        Иначе
            соотКон=НовыйСоответствиеСтруктура();
            соотКон.Вставить("x",рКоординатыНач.x);
            соотКон.Вставить("y",рКоординатыНач.y+20);
            мКоординат.Добавить(соотКон);
        КонецЕсли;
        //
        // случай, когда линия идет снизу на верхнюю границу (ставим точку середины)
        Если рКонец<>0 и СоотСвойство(мКоординат[0],"y","Число") > СоотСвойство(мКоординат[1],"y","Число") И СоотСвойство(струЭлемента,"portIndexTo","Число")=2 Тогда
            х1=РассчитатьКоординатыЭлемента(рПараметры.Схема,СоотСвойство(струЭлемента,"connectFromItemId","Число"),3).x;
            х2=РассчитатьКоординатыЭлемента(рПараметры.Схема,СоотСвойство(струЭлемента,"connectToItemId","Число"),1).x;
            Если х1<>Неопределено и х2<>Неопределено Тогда
                xmid=Цел((х1+х2)/2);
                рВертШагСетки=СоотСвойство(СоотСвойство(рПараметры.Схема,"#value"),"gridVerticalStep");
                ymid=СоотСвойство(мКоординат[1],"y","Число")-рВертШагСетки;
                соотСред=НовыйСоответствиеСтруктура();
                соотСред.Вставить("x",xmid);
                соотСред.Вставить("y",ymid);
                мКоординат.Вставить(1,соотСред);
            КонецЕсли;            
        КонецЕсли;
        //
        струЭлемента.Вставить("point",мКоординат);
        
    Иначе
        // координаты и размер
        //Если рКоординаты.Лево=Неопределено И рКоординаты.Верх<>Неопределено Тогда // ищем максимальный X
        //    рКоординаты.Лево=ПолучитьМаксимальноеЗначениеКлючаВМассивеСтруктур(струСхемы.item,"rectRight") + струСхемы.gridHorizontalStep;
        //КонецЕсли;
        //Если рКоординаты.Верх=Неопределено И рКоординаты.Лево<>Неопределено Тогда // ищем максимальный Y
        //    рКоординаты.Верх=ПолучитьМаксимальноеЗначениеКлючаВМассивеСтруктур(струСхемы.item,"rectBottom") + струСхемы.gridVerticalStep;
        //КонецЕсли;
        струЭлемента.Вставить("rectLeft",рПараметры.Лево);
        струЭлемента.Вставить("rectTop",рПараметры.Верх);
        струЭлемента.Вставить("rectRight",рПараметры.Лево+рПараметры.Ширина);
        струЭлемента.Вставить("rectBottom",рПараметры.Верх+рПараметры.Высота);
        РасставитьТочкиФигурыЭлемента(струЭлемента);
        
    КонецЕсли;
    
Исключение
    Сообщить("УстановитьКоординатыЭлементаСхемы, общая ошибка: "+ОписаниеОшибки(),СтатусСообщения.Важное);
КонецПопытки;
КонецПроцедуры    

// Собственно готови данные для отрисовки конкретной фигуры элемента ГС. Вспомогательная для УстановитьКоординатыЭлементаСхемы.
//
// Параметры:
//    струЭлемента - структура/соответствие, соответствующая типу элемента (определяемая ранее в ПостроитьСтруктуруДляТипаЭлементаСхемы);
//    рМодификатор - число; до 10 включительно совпадает с нотацией типа элемента ГС, значения с 11 по 13 - нетипичные геометрические фигуры.
//
Процедура РасставитьТочкиФигурыЭлемента(струЭлемента,рМодификатор=Неопределено)
Попытка
    itemType=?(рМодификатор=Неопределено,СоотСвойство(струЭлемента,"itemType","Число"),рМодификатор);
    //
    rectLeft=СоотСвойство(струЭлемента,"rectLeft","Число");
    rectTop=СоотСвойство(струЭлемента,"rectTop","Число");
    rectRight=СоотСвойство(струЭлемента,"rectRight","Число");
    rectBottom=СоотСвойство(струЭлемента,"rectBottom","Число");
    
    мТочек1=Новый Массив;
    
    Если itemType=0 ИЛИ itemType=5 ИЛИ itemType=9 ИЛИ itemType=10 Тогда // Декорация/Действие/Обработка/ВложенныйПроцесс: Прямоугольник
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,rectTop));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1,rectTop));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1,rectBottom-1));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,rectBottom-1));
        //
    ИначеЕсли itemType=2 Тогда // Старт: Прямоугольник + треугольник снизу (высота треугольника=5)
        dy=Цел((rectRight-rectLeft)/2/Sqrt(3));
        dy=?(rectBottom-dy<=rectTop,Цел((rectBottom-rectTop)/2),dy); // корректировка запредельных значений
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,rectTop));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1,rectTop));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1,rectBottom-dy));
        мТочек1.Добавить(Новый Структура("x,y",Цел((rectLeft+rectRight)/2),rectBottom-1));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,rectBottom-dy));
        //
    ИначеЕсли itemType=3 Тогда // Завершение: Прямоугольник + треугольник сверху (высота треугольника=5)
        dy=Цел((rectRight-rectLeft)/2/Sqrt(3));
        dy=?(rectTop+dy>=rectBottom,Цел((rectRight-rectLeft)/2),dy); // корректировка запредельных значений
        мТочек1.Добавить(Новый Структура("x,y",Цел((rectLeft+rectRight)/2),rectTop));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1,rectTop+dy));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1,rectBottom-1));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,rectBottom-1));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,rectTop+dy));
        //
    ИначеЕсли itemType=4 Тогда // Условие: Шестиугольник (расчет середины высоты:dy/2,угол 60 градусов) 
        dx=Цел((rectBottom-rectTop)/2/Sqrt(3)); // ДельтаX при 60 градусном уклоне
        dx=?(2*dx>(rectRight-rectLeft),Цел((rectRight-rectLeft)/4),dx); // корректировка запредельных значений
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,Цел((rectTop+rectBottom)/2)));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft+dx,rectTop));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1-dx,rectTop));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1,Цел((rectTop+rectBottom)/2)));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1-dx,rectBottom-1));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft+dx,rectBottom-1));
        //
    ИначеЕсли itemType=6 Тогда // ВыборВарианта: Прямоугольник
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,rectTop));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1,rectTop));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1,rectBottom-1));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,rectBottom-1));
        //
    ИначеЕсли itemType=7 Тогда // Разделение: Треугольник, острый угол вниз
        dx=Цел((rectRight-rectLeft)/2)-1;
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,rectTop));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft+2*dx,rectTop));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft+dx,rectBottom-1));
        //
    ИначеЕсли itemType=8 Тогда // Слияние: Треугольник, острый угол вверх
        dx=Цел((rectRight-rectLeft)/2)-1;
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,rectBottom-1));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft+2*dx,rectBottom-1));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft+dx,rectTop));    
        //
    ИначеЕсли itemType=11 Тогда // (нетиповые фигуры) Галстук - бабочка
        dx=Цел((rectBottom-rectTop)/2/Sqrt(3)); // ДельтаX при 60 градусном уклоне
        dx=?(2*dx>(rectRight-rectLeft),Цел((rectRight-rectLeft)/4),dx); // корректировка запредельных значений
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,Цел((rectTop+rectBottom)/2)));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft+dx,rectTop));
        мТочек1.Добавить(Новый Структура("x,y",Цел((rectLeft+rectRight)/2),Цел((rectTop+rectBottom)/2)));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1-dx,rectTop));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1,Цел((rectTop+rectBottom)/2)));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1-dx,rectBottom-1));
        мТочек1.Добавить(Новый Структура("x,y",Цел((rectLeft+rectRight)/2),Цел((rectTop+rectBottom)/2)));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft+dx,rectBottom-1));
        //
    ИначеЕсли itemType=12 Тогда // (нетиповые фигуры) Звезда шерифа
        // сторона маленького треугольника
        dc=Цел((rectRight-rectLeft)/3);
        dchalf=Цел(dc/2);
        dchigh=Цел(dchalf*Sqrt(3));
        //dx=Цел((rectBottom-rectTop)/2/Sqrt(3)); // ДельтаX при 60 градусном уклоне
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,rectTop+dchigh));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft+dc,rectTop+dchigh));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft+dc+dchalf,rectTop));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1-dc,rectTop+dchigh));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1,rectTop+dchigh));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1-dchalf,rectTop+2*dchigh));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1,rectTop+3*dchigh));
        мТочек1.Добавить(Новый Структура("x,y",rectRight-1-dc,rectTop+3*dchigh));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft+dc+dchalf,rectBottom-1));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft+dc,rectTop+3*dchigh));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft,rectTop+3*dchigh));
        мТочек1.Добавить(Новый Структура("x,y",rectLeft+dchalf,rectTop+2*dchigh));
        //
    ИначеЕсли itemType=13 Тогда // (нетиповые фигуры) Круг
        // сторона маленького треугольника
        radius=Мин(Цел((rectRight-rectLeft)/2),Цел((rectBottom-rectTop)/2));
        xcenter=rectLeft + radius;
        ycenter=rectTop + radius;
        pi=3.141592635897;
        НачУгол=-20;
        КонУгол=200;
        ШагГрад=10;
        у=НачУгол;
        Пока у<=КонУгол Цикл
            Угол=у*pi/180;
            x=Окр(Cos(Угол)*radius);
            y=Окр(Sin(Угол)*radius);
            мТочек1.Добавить(Новый Структура("x,y",xcenter+x,ycenter+y));
            у=у + ШагГрад;
        КонецЦикла;
        //
    КонецЕсли;
    
    Если ТипЗнч(НовыйСоответствиеСтруктура())=Тип("Соответствие") Тогда // преобразуем
        мТочек2=Новый Массив;
        Для каждого рТочка1 Из мТочек1 Цикл
            соот=Новый Соответствие;
            Для каждого киз Из рТочка1 Цикл
                соот.Вставить(киз.Ключ,киз.Значение);
            КонецЦикла;
            мТочек2.Добавить(соот);
        КонецЦикла;
    Иначе
        мТочек2=мТочек1;
    КонецЕсли;
    
    струЭлемента.Вставить("point",мТочек2);
    
Исключение
    Сообщить("РасставитьТочкиФигурыЭлемента, общая ошибка: "+ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры

// Устанавливает элементу ГС заголовок без локализации языка, по умолчанию.
//
// Параметры:
//    струЭлемента - структура/соответствие, соответствующая типу элемента (определяемая ранее в ПостроитьСтруктуруДляТипаЭлементаСхемы);
//    рЗаголовок - строка, произвольная надпись на элементе.
//
Процедура УстановитьЗаголовокЭлементаСхемы(струЭлемента,рЗаголовок) Экспорт
    соот=НовыйСоответствиеСтруктура();
    соот.Вставить("lang","#");
    соот.Вставить("content",рЗаголовок);
    мЗаголовка=СоотСвойство(струЭлемента,"itemTitle");
    Если ТипЗнч(мЗаголовка)<>Тип("Массив") Тогда мЗаголовка=Новый Массив КонецЕсли;
    мЗаголовка.Добавить(соот);
    струЭлемента.Вставить("itemTitle",мЗаголовка);
КонецПроцедуры

// Добавляет структуру, описывающую элемент ГС, в соответствующую коллекцию элементов самой структуры ГС.
// Возвращает уникальный в пределах схемы id добавленного элемента, 1 и более. При ошибке возвращает Неопределено.
//
// Параметры:
//    рСхема - соответствие структур, массивов и прочих коллекций, созданное ИнициализироватьСхему и заполненное в ходе построения схемы;
//    струЭлемента - структура/соответствие, соответствующая типу элемента (определяемая ранее в ПостроитьСтруктуруДляТипаЭлементаСхемы).
//
Функция ДобавитьЭлементВСхему(рСхема,струЭлемента) Экспорт
Попытка
    рИмяЭлемента=СокрЛП(СоотСвойство(струЭлемента,"itemCode"));
    струИмеющегося=ПолучитьЭлементСхемыПоИмени(рСхема,рИмяЭлемента);
    Если струИмеющегося<>Неопределено Тогда // такой уже есть
        Возврат СоотСвойство(струИмеющегося,"itemId","Число");
    КонецЕсли;
    
    струСхемы=Неопределено;
    мЭлементовГС=ПолучитьКоллекциюЭлементовСхемы(рСхема,струСхемы);
    
    // Ищем максимальный itemId
    струЭлемента.Вставить("itemId",ПолучитьМаксимальноеЗначениеСвойства(мЭлементовГС,"itemId")+1);
    
    // Ищем такой же itemCode (заимствованный код; возможно, нужен рефакторинг!)
    //Если НайтиПоЗначениюКлючаВМассивеСтруктур(струСхемы.item,"itemCode",струЭлемента.itemCode) <> Неопределено Тогда
    //    _базоваяЧасть=струЭлемента.itemCode;
    //    _нс=1;
    //    Пока НайтиПоЗначениюКлючаВМассивеСтруктур(струСхемы.item,"itemCode",_базоваяЧасть + Формат(_нс,"ЧГ=")) <> Неопределено Цикл
    //        _нс=_нс + 1;
    //    КонецЦикла;
    //    струЭлемента.itemCode=_базоваяЧасть + Формат(_нс,"ЧГ=");
    //КонецЕсли;
    
    // Ищем максимальный itemTabOrder
    // пока так. Это порядок обхода. Возможно нужно более продвинутое вычисление сделать 
    // (считать все подчиненные и соединенные элементы последнего и прибавлять на их количество к максимальному)
    струЭлемента.Вставить("itemTabOrder",ПолучитьМаксимальноеЗначениеСвойства(мЭлементовГС,"itemTabOrder")+5);
    
    // Ищем максимальный zOrder
    струЭлемента.Вставить("zOrder",ПолучитьМаксимальноеЗначениеСвойства(мЭлементовГС,"zOrder",-1)+1);
    
    // собственно добавление в коллекцию элементов схемы
    мЭлементовГС.Добавить(струЭлемента);
    
    струСхемы.Вставить("item",мЭлементовГС);
    рСхема.Вставить("#value",струСхемы);
    
    Возврат СоотСвойство(струЭлемента,"itemId","Число");
Исключение
    Сообщить("ДобавитьЭлементВСхему, общая ошибка: "+ОписаниеОшибки(),СтатусСообщения.Важное);
    Возврат Неопределено;
КонецПопытки;
КонецФункции

// Добавляет вариант в элемент типа "Выбор". Элемент уже должен быть инициализирован. Возвращает порядковый номер варианта, начиная с 0.
// При ошибке возвращает Неопределено.
//
// Параметры:
//    струЭлемента - структура/соответствие, соответствующая типу элемента (определяемая ранее в ПостроитьСтруктуруДляТипаЭлементаСхемы);
//    рИмяВарианта - строка, имя варианта, уникальное в пределах выбора;
//    рЗаголовокВарианта - строка, произвольная надпись на варианте.
//
Функция ДобавитьВариантВыбора(струЭлемента,рИмяВарианта,рЗаголовокВарианта) Экспорт
Попытка
    соотЗаголовка=НовыйСоответствиеСтруктура();
    соотЗаголовка.Вставить("lang","#");
    соотЗаголовка.Вставить("content",рЗаголовокВарианта);
    мЗаголовка=Новый Массив;
    мЗаголовка.Добавить(соотЗаголовка);
    
    соотВарианта=НовыйСоответствиеСтруктура();
    соотВарианта.Вставить("name",рИмяВарианта);
    соотВарианта.Вставить("description",мЗаголовка);    
    соотВарианта.Вставить("backColor",СоотСвойство(струЭлемента,"backColor"));
    
    мВариантов=СоотСвойство(струЭлемента,"transition");
    Если ТипЗнч(мВариантов)<>Тип("Массив") Тогда мВариантов=Новый Массив КонецЕсли;
    мВариантов.Добавить(соотВарианта);
    
    струЭлемента.Вставить("transition",мВариантов);
    Возврат мВариантов.Количество()-1;
Исключение
    Сообщить("ДобавитьВариантВыбора, общая ошибка: "+ОписаниеОшибки());
    Возврат Неопределено;
КонецПопытки;
КонецФункции

// Получает координаты для работы с портом (точкой входа/выхода соединительной линии); возвращает структуру с ключами x,y;
// используется при первичной работе со схемой (далее можно обращаться к свойствам элемента как объекта);
// При ошибке возвращает Неопределено.
//
// Параметры:
//    рСхема - соответствие структур, массивов и прочих коллекций, созданное ИнициализироватьСхему и заполненное в ходе построения схемы;
//    itemId - уникальный в пределах схемы идентификатор элемента;
//    portIndex - код типа стороны элемента получателя (см. ПреобразоватьТипСтороныЭлементаВЧисло), ни в коем случае убирать "Знач"!
//    connectFromPortIndex - код типа стороны элемента отправителя (см. ПреобразоватьТипСтороныЭлементаВЧисло), изменяется внутри функции.
//
Функция РассчитатьКоординатыЭлемента(рСхема,itemId,Знач portIndex,connectFromPortIndex=0)
Попытка
    рРезультат=Новый Структура("x,y",0,0);
    
    струСхемы=Неопределено;
    мЭлементовГС=ПолучитьКоллекциюЭлементовСхемы(рСхема,струСхемы);
    Если мЭлементовГС.Количество()=0 Тогда
        Сообщить("Внутренняя ошибка: коллекция элементов схемы пуста!",СтатусСообщения.Важное);
    Иначе
        струЭлемента=НайтиПоЗначениюКлючаВМассивеСтруктур(мЭлементовГС,"itemId",itemId);
        Если струЭлемента=Неопределено Тогда
            Сообщить("Внутренняя ошибка: элемент не найден по своему id "+СокрЛП(itemId)+"!",СтатусСообщения.Важное);
            Возврат рРезультат;
        КонецЕсли;
    КонецЕсли;
    
    // Порты:
    //1: Лево 
    //2: Верх 
    //3: Право 
    //4: Низ 
    //5: Центр 
    //6: Вариант 1 Лево 
    //7: Вариант 1 Право 
    //8: Вариант 2 Лево 
    //9: Вариант 2 Право
    // Каждый вариант - это 18 точек по шкале Y от rectBottom. Середина=rectBottom - (18/2)
    
    dy=0;
    Если portIndex > 5 Тогда
        caseCount=СоотСвойство(струЭлемента,"transition").Количество();
        connectFromPortIndex=Цел((portIndex-6)/2);
        portIndex=1 + (portIndex%2)*2;
        dy=(caseCount - connectFromPortIndex - 1)*18 + 18/2;
    КонецЕсли;
    
    рЛево=СоотСвойство(струЭлемента,"rectLeft","Число");
    рВерх=СоотСвойство(струЭлемента,"rectTop","Число");
    рПраво=СоотСвойство(струЭлемента,"rectRight","Число");
    рНиз=СоотСвойство(струЭлемента,"rectBottom","Число");
    
    Если portIndex=1 Тогда
        рРезультат.x=рЛево;
        рРезультат.y=?(dy>0,рНиз-1-dy,Цел((рВерх+рНиз+1)/2));
    ИначеЕсли portIndex=2 Тогда
        рРезультат.x=Цел((рЛево+рПраво+1)/2);
        рРезультат.y=рВерх;
    ИначеЕсли portIndex=3 Тогда
        рРезультат.x=рПраво;
        рРезультат.y=?(dy>0,рНиз-1-dy,Цел((рВерх+рНиз+1)/2));
    ИначеЕсли portIndex=4 Тогда
        рРезультат.x=Цел((рЛево+рПраво+1)/2);
        рРезультат.y=рНиз;
    ИначеЕсли portIndex=5 Тогда
        рРезультат.x=Цел((рЛево+рПраво+1)/2);
        рРезультат.y=Цел((рВерх+рНиз+1)/2);
    КонецЕсли;
    
    Возврат рРезультат;
Исключение
    Сообщить("РассчитатьКоординатыЭлемента, общая ошибка: "+ОписаниеОшибки());
    Возврат Неопределено;
КонецПопытки;
КонецФункции

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


#Область ДействияВторичнойНастройки

// Действия вторичной настройки полезны, когда объект "ГрафическаяСхема" уже есть, и надо изменить свойство элемента, не имеющее во встроенном языке 
// возможности записи, т.е. которые только на чтение. Важно: вторичная работа ведётся уже с соответствиями, а не со структурами, т.е. все коллекции данных,
// бывшие структурами при первичном построении, теперь будут являться соответствиями.
// Используется сериализация схемы в строку, чтение строки через JSON в коллекцию коллекций, и работа с их элементами и значениями.
// Рекомендуется использовать РазобратьГрафическуюСхему, затем выполнить настройку нужных свойств, затем СобратьГрафическуюСхему.

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

// Устанавливает ZOrder (порядок плана отображения относительно других перекрывающих фигур) для всех элементов указанного типа.
//
// Параметры:
//    рСхема - соответствие структур, массивов и прочих коллекций, созданное ИнициализироватьСхему и заполненное в ходе построения схемы, или сериализованное из ГС;
//    рТипЭлемента - число (от 0 до 10), строковое представление типа или Тип элемента ГС (например, Тип("ЭлементГрафическойСхемыДействие"));
//    ZOrder - число, приоритет по возрастанию (старший накрывает младших), изменяется внутри процедуры.
//
Процедура УстановитьZOrderВсемЭлементам(рСхема,рТипЭлемента,ZOrder) Экспорт
Попытка        
    рКодТипаЭлемента=ПолучитьКодТипаЭлементаСхемы(рТипЭлемента);
    Если рКодТипаЭлемента=Неопределено Тогда Возврат КонецЕсли;
    
    знчСхемы=Неопределено;
    мЭлементовГС=ПолучитьКоллекциюЭлементовСхемы(рСхема,знчСхемы);
    Если мЭлементовГС.Количество()=0 Тогда Возврат КонецЕсли; // нет ни одного элемента
    //
    Для каждого рЭлементГС из мЭлементовГС цикл
        Если СоотСвойство(рЭлементГС,"itemType","Число")=рКодТипаЭлемента Тогда
            рЭлементГС.Вставить("zOrder",ZOrder);
            ZOrder=ZOrder+1;
        КонецЕсли;
    КонецЦикла;
    
    знчСхемы.Вставить("item",мЭлементовГС);
    рСхема.Вставить("#value",знчСхемы);
Исключение
    Сообщить("УстановитьZOrderВсемЭлементам, общая ошибка: "+ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры

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

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

// Удаляет элемент из коллекции элементов схемы, в т.ч. при необходимости и связанные с ним.
//
// Параметры:
//    рСхема - соответствие структур, массивов и прочих коллекций, созданное ИнициализироватьСхему и заполненное в ходе построения схемы, или сериализованное из ГС;
//    рИмяЭлемента - строка, уникальное имя элемента в пределах схемы;
//    рУдалятьСвязанныеЛинии - булево; имеет смысл только при удалении фигуры (не Линии), по умолчанию Ложь;
//        если Истина, то линии, входящие в фигуру и исходящие из неё, также будут удалены;
//        если Ложь, то линии, входящие в фигуру и исходящие из неё, будут вести "в никуда" (в связочные id ставится -1).
//
Процедура УдалитьЭлементСхемыПоИмени(рСхема,рИмяЭлемента,рУдалятьСвязанныеЛинии=Ложь) Экспорт
Попытка
    знчСхемы=Неопределено;
    мЭлементовГС=ПолучитьКоллекциюЭлементовСхемы(рСхема,знчСхемы);
    Если мЭлементовГС.Количество()=0 Тогда Возврат КонецЕсли; // нет ни одного элемента
    
    мНенужных=Новый Массив;
    пози=Неопределено;
    Для й=0 По мЭлементовГС.Количество()-1 Цикл
        Если СокрЛП(СоотСвойство(мЭлементовГС[й],"itemCode"))=рИмяЭлемента Тогда
            мНенужных.Добавить(мЭлементовГС.Получить(й)); Прервать;
        КонецЕсли;
    КонецЦикла;
    Если мНенужных.Количество()=1 Тогда
        рУдаляемый=мНенужных.Получить(0);
        рТипЭлемента=СоотСвойство(рУдаляемый,"itemType","Число");
        Если рТипЭлемента=Неопределено Тогда Возврат КонецЕсли;
        Если рТипЭлемента=1 Тогда // это линия
            // пока ничего не делаем
        Иначе
            идФигуры=СоотСвойство(рУдаляемый,"itemId","Число");
            Для каждого рЭлемент Из мЭлементовГС Цикл
                Если СоотСвойство(рЭлемент,"itemType","Число")<>1 Тогда Продолжить КонецЕсли; // не линия
                Если СоотСвойство(рЭлемент,"connectFromItemId","Число")=идФигуры Тогда
                    Если рУдалятьСвязанныеЛинии Тогда
                        мНенужных.Добавить(рЭлемент);
                    Иначе
                        рЭлемент.Вставить("connectFromItemId",-1); // обрезаем
                    КонецЕсли;                    
                КонецЕсли;
                Если СоотСвойство(рЭлемент,"connectToItemId","Число")=идФигуры Тогда
                    Если рУдалятьСвязанныеЛинии Тогда
                        мНенужных.Добавить(рЭлемент);
                    Иначе
                        рЭлемент.Вставить("connectToItemId",-1); // обрезаем
                    КонецЕсли;                    
                КонецЕсли;
            КонецЦикла; // по поиску линий, связанных с удаляемой фигурой
        КонецЕсли; // если удаляется фигура/линия
    КонецЕсли;
    //
    // собственно удаляем
    Для каждого рЭлемент Из мНенужных Цикл
        мЭлементовГС.Удалить(мЭлементовГС.Найти(рЭлемент));
    КонецЦикла;
    
    знчСхемы.Вставить("item",мЭлементовГС);
    рСхема.Вставить("#value",знчСхемы);
Исключение
    Сообщить("УдалитьЭлементСхемыПоИмени, общая ошибка: "+ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры

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

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

// Удаляет элемент ВариантаВыбора по её имени или порядковому номеру среди вариантов из массива вариантов выбора.
// Если варианта с таким именем/номером нет, ничего не делает.
//
// Параметры:
//    рЭлемент - структура/соответствие, соответствующая типу элемента (определяемая ранее в ПостроитьСтруктуруДляТипаЭлементаСхемы);
//    рИмяИлиНомер - строковое имя или числовой номер (от 0 по возрастанию в порядке №№ вариантов в выборе).
//
Процедура УдалитьВариантВыбораПоИмениИлиНомеру(рЭлемент,рИмяИлиНомер) Экспорт
Попытка
    мВариантов=СоотСвойство(рЭлемент,"transition");
    Если ТипЗнч(мВариантов)<>Тип("Массив") Тогда Возврат КонецЕсли;
    //
    Если ТипЗнч(рИмяИлиНомер)=Тип("Строка") Тогда // по имени
        пози=Неопределено;
        Для й=0 По мВариантов.Количество()-1 Цикл
            рВариант=мВариантов.Получить(й);
            Если СокрЛП(СоотСвойство(рВариант,"name"))=СокрЛП(рИмяИлиНомер) Тогда
                пози=й; Прервать;
            КонецЕсли;
        КонецЦикла;        
    ИначеЕсли ТипЗнч(рИмяИлиНомер)=Тип("Число") Тогда
        Если мВариантов.Количество()<=рИмяИлиНомер Тогда Возврат КонецЕсли;
        пози=рИмяИлиНомер;
    Иначе
        Возврат;
    КонецЕсли;
    //
    Если пози<>Неопределено Тогда
        мВариантов.Удалить(пози);
        рЭлемент.Вставить("transition",мВариантов);
    КонецЕсли;    
    //
Исключение
    Сообщить("УдалитьВариантВыбораПоИмениИлиНомеру, общая ошибка: "+ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры    
    
#КонецОбласти


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

// Преобразует графическую схему в соответствие соответствий и массивов. Возвращает соответствие.
// Внимание! Даже если ранее в свойствах коллекций были структуры, они заменятся на соответствия, т.к. только такое восстановление из JSON возможно.
// Дописывает служебные поля: в коллекцию самой схемы дописывает СтруктурыТиповЭлементов (кэш структур всех типов элементов ГС),
// в коллекцию каждого элемента ГС дописывает Имя (строковое имя элемента) и Тип (тип в нотации 1С, например, Тип("ЭлементГрафическойСхемыДействие")).
// При ошибке возвращает Неопределено.
//
// Параметры:
//    рГС - объект типа "Графическая схема".
//
Функция РазобратьГрафическуюСхему(рГС) Экспорт
Попытка
    // нормализуем ГС (по неизвестным причинам, обратная сериализация не понимает, например. жирный шрифт)
    рШрифт=Новый Шрифт; // по умолчанию (восстанавливать оформление, если надо, потом и другими средствами)
    Для каждого рЭлементГС Из рГС.ЭлементыГрафическойСхемы Цикл
        Попытка рЭлементГС.Шрифт=рШрифт Исключение КонецПопытки;
    КонецЦикла;
    
    // сериализуем ГС
    рЗапись=Новый ЗаписьJSON;
    рЗапись.УстановитьСтроку();
    СериализаторXDTO.ЗаписатьJSON(рЗапись,рГС,НазначениеТипаXML.Явное);
    //
    строСхемы=рЗапись.Закрыть();
    //сообщить("Разборка: "+Символы.ПС+стросхемы);
    //
    // приводим из строки JSON в коллекцию (все структуры будут отражены как соответствия!)
    рЧтение=Новый ЧтениеJSON;
    рЧтение.УстановитьСтроку(строСхемы);
    рСхема=ПрочитатьJSON(рЧтение,Истина);
    
    Если ТипЗнч(рСхема)<>Тип("Соответствие") Тогда Возврат Неопределено КонецЕсли;
    
    // добавляем служебные поля
    рСхема.Вставить("СтруктурыТиповЭлементов",ПостроитьКэшСтруктурВсехТиповЭлементовСхемы());
    
    // добавляем служебные тип и имя к каждому элементу и вносим всё обратно в схему
    знчСхемы=Неопределено;
    мЭлементовГС=ПолучитьКоллекциюЭлементовСхемы(рСхема,знчСхемы);
    Если мЭлементовГС.Количество()>0 Тогда
        спТипов=ПостроитьНотациюТиповЭлементовСхемы();
        Для каждого рЭлементГС Из мЭлементовГС Цикл
            рЭлементГС.Вставить("Имя",СоотСвойство(рЭлементГС,"itemCode"));
            знчТип=спТипов.НайтиПоЗначению(СоотСвойство(рЭлементГС,"itemType","Число"));
            Если знчТип<>Неопределено Тогда
                рЭлементГС.Вставить("Тип",    Тип("ЭлементГрафическойСхемы"+СокрЛП(знчТип.Представление)));
            Иначе
                рЭлементГС.Вставить("Тип",Неопределено);
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    //            
    знчСхемы.Вставить("item",мЭлементовГС);
    рСхема.Вставить("#value",знчСхемы);
    
    Возврат рСхема;    
Исключение
    Сообщить("РазобратьГрафическуюСхему, общая ошибка: "+ОписаниеОшибки());
    Возврат Неопределено;
КонецПопытки;
КонецФункции    

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

Кому пригодится или кого заинтересует - будет хорошо.

Ещё раз спасибо гигантам, на плечах которых стоит это решение. В первую очередь Diversus'у, высказавшему идею ещё в далёкие времена.

 

 

Скачать файлы

Наименование Файл Версия Размер
Программная работа с графическими схемами. Готовое решение.:

.epf 86,47Kb
17.02.18
20
.epf 86,47Kb 20 Скачать

Специальные предложения

Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. genayo 18.02.18 17:48 Сейчас в теме
А можно рассказать о практическом применении, если не трудно?
2. triviumfan 21 18.02.18 18:36 Сейчас в теме
(1)
Концепцию взял у //infostart.ru/public/551576/ и допилил под свой извращённый вкус.

Вроде все понятно, любит извращения. А для рисования есть другое ПО :)
3. Yashazz 3329 18.02.18 20:17 Сейчас в теме
(1) Ну, одно из интересных применений, авось, в ближайшие недели 2-3 выложу как отдельную публикацию, а вообще, например, визуализация сценариев работы сотрудников колл-центра. Последовательности вопросов при общении с клиентами. А вот что стало самым главным заказом, я рассказать не смогу, т.к. заказчиком выступает ФНС и всё секретно)

(2) Для рисования таких схем есть Visio, но плюсы схем в 1С, думаю, очевидны. Какое ещё ПО вы знаете? Можете ли предложить готовое решение работы с ним?
4. pm74 176 18.02.18 20:45 Сейчас в теме
(0) тема интересная плюсанул , поразбираюсь на досуге
с визуализацией в 1с плохо - это факт
поэтому на ИС традиционно высок интерес к разным штуковинам на javascript или наподобие этой
мои 5 коп. на тему применимости см. рис. (до правильной программной компоновки тоже руки пока не дошли)
Прикрепленные файлы:
5. Yashazz 3329 19.02.18 11:18 Сейчас в теме
(4) А вот этот замечательный скриншот - он руками был сделан? Можно подробнее в личку?
6. pm74 176 19.02.18 11:48 Сейчас в теме
(5)
он руками был сделан

нет ну что вы , конечно программно
сделал по мотивам какой то публикации, к сожалению не помню авторства
используется для формирования схемы ДКАпо таблице переходов

&НаСервере
Функция НоваяТочкаXDTO(x,y) 	Точка=СериализаторXDTO.Фабрика.Создать(СериализаторXDTO.Фабрика.Тип("http://v8.1c.ru/8.2/data/graphscheme","Point"));
	Точка.x=x;
	Точка.y=y;	
	Возврат Точка;
КонецФункции
&НаСервере
Функция НовыйОбъектXDTO(Тип,ИмяЭлемента,Верх,Лево,Высота,Ширина,Содержание,Фигура,Цвет=Неопределено,Шрифт=Неопределено,LastID=0)Экспорт
	НО=СериализаторXDTO.Фабрика.Создать(СериализаторXDTO.Фабрика.Тип("http://v8.1c.ru/8.2/data/graphscheme","GraphSchemeItem"));
	НО.itemType=Тип;
	НО.itemCode=ИмяЭлемента;
	НО.itemId=LastID;
	НО.zOrder=LastID;
	LastID=LastID+1;
	НО.itemTabOrder=1;
	НО.rectLeft=Лево;
	НО.rectRight=Лево+Ширина;
	НО.rectTop=Верх;
	НО.rectBottom=Верх+Высота;
	НО.Border=СериализаторXDTO.ЗаписатьXDTO(Новый Линия(ТипСоединительнойЛинии.Сплошная,1));
	НО.Point.Добавить(НоваяТочкаXDTO(НО.rectLeft,НО.rectTop));
	НО.Point.Добавить(НоваяТочкаXDTO(НО.rectRight-1,НО.rectTop));
	НО.Point.Добавить(НоваяТочкаXDTO(НО.rectRight-1,НО.rectBottom-1));
	НО.Point.Добавить(НоваяТочкаXDTO(НО.rectLeft,НО.rectBottom-1));
	Заголовки=СериализаторXDTO.Фабрика.Создать(СериализаторXDTO.Фабрика.Тип("http://v8.1c.ru/8.1/data/core","LocalStringType"));
	ЗаголовокЭлемента=СериализаторXDTO.Фабрика.Создать(СериализаторXDTO.Фабрика.Тип("http://v8.1c.ru/8.1/data/core","LocalStringItemType"));
	ЗаголовокЭлемента.lang="#";
	ЗаголовокЭлемента.content=Содержание;
	Заголовки.Item.Добавить(ЗаголовокЭлемента);
	НО.itemTitle=Заголовки;
	Примечания=СериализаторXDTO.Фабрика.Создать(СериализаторXDTO.Фабрика.Тип("http://v8.1c.ru/8.1/data/core","LocalStringType"));
	Примечание=СериализаторXDTO.Фабрика.Создать(СериализаторXDTO.Фабрика.Тип("http://v8.1c.ru/8.1/data/core","LocalStringItemType"));
	Примечание.lang="#";
	Примечание.content=Содержание;
	Примечания.Item.Добавить(Примечание);
	НО.tipText=Примечания;
	НО.currentLanguage="#";
	НО.shape=Фигура;
	Если Цвет=Неопределено Тогда
		НО.backColor=Новый Цвет;
	Иначе
		НО.backColor=Новый Цвет(Цвет[0],Цвет[1],Цвет[2]);
	КонецЕсли;
	
	Если Не Шрифт=Неопределено Тогда
		НО.textFont=СериализаторXDTO.ЗаписатьXDTO(Шрифт);
		
	КонецЕсли;	
	Возврат НО;
КонецФункции
&НаСервере
Функция НоваяЛинияXDTO(ГрафСхемаXDTO,ПервыйЭлемент,ВторойЭлемент,Содержание,Подсказка,ПортВыхода=Неопределено,ПортВхода=Неопределено,LastID=0,Цвет=Неопределено)Экспорт
	НО=СериализаторXDTO.Фабрика.Создать(СериализаторXDTO.Фабрика.Тип("http://v8.1c.ru/8.2/data/graphscheme","GraphSchemeItem"));
	НО.itemType=1;
	НО.itemId=LastID+100;
	//НО.zOrder=LastID+100;
	LastID=LastID+1;
	НО.itemTabOrder=2;
	НО.itemCode=Подсказка;
	Заголовки=СериализаторXDTO.Фабрика.Создать(СериализаторXDTO.Фабрика.Тип("http://v8.1c.ru/8.1/data/core","LocalStringType"));
	ЗаголовокЭлемента=СериализаторXDTO.Фабрика.Создать(СериализаторXDTO.Фабрика.Тип("http://v8.1c.ru/8.1/data/core","LocalStringItemType"));
	ЗаголовокЭлемента.lang="#";
	ЗаголовокЭлемента.content=Содержание;
	Заголовки.Item.Добавить(ЗаголовокЭлемента);
	НО.itemTitle=Заголовки;
	НО.currentLanguage="#";
	НО.textPos="Middle";
	НО.beginArrowStyle=СтильСтрелки.Нет;
	НО.endArrowStyle=СтильСтрелки.Незаполненная;
	НО.lineColor=Цвет;
	
	ДанныеПервый=ПортыЭлементаXDTO(ГрафСхемаXDTO,ПервыйЭлемент);
	ДанныеВторой=ПортыЭлементаXDTO(ГрафСхемаXDTO,ВторойЭлемент);
	
	НО.connectFromItemId=ДанныеПервый.itemId;
	НО.connectToItemId=ДанныеВторой.itemId;
	НО.connectFromPortIndex=0;
	
	Если ПортВыхода=Неопределено Или ПортВхода=Неопределено Тогда
		Если ДанныеПервый.itemId<ДанныеВторой.itemId Тогда
			ПортВыхода=2;ПортВхода=2;
		ИначеЕсли ДанныеПервый.itemId>ДанныеВторой.itemId Тогда 
			ПортВыхода=4; ПортВхода=4;
		Иначе 
			ПортВыхода=1; ПортВхода=2;
		КонецЕсли;
	КонецЕсли;	
	
	НО.portIndexFrom=ПортВыхода;
	НО.portIndexTo=ПортВхода;
	НО.backColor=новый Цвет;
	НО.decorativeLine=Истина;
	НО.textFont=СериализаторXDTO.ЗаписатьXDTO(новый Шрифт("Calibri",10,,Истина));
	НО.textColor=Цвет;
	НО.Border=СериализаторXDTO.ЗаписатьXDTO(новый Линия(ТипСоединительнойЛинии.Сплошная,1));
	НО.Point.Добавить(НоваяТочкаXDTO(ДанныеПервый["port"+ПортВыхода+"x"],ДанныеПервый["port"+ПортВыхода+"y"]));
	НО.Point.Добавить(НоваяТочкаXDTO(ДанныеВторой["port"+ПортВхода+"x"],ДанныеВторой["port"+ПортВхода+"y"]));	
	Возврат НО;
КонецФункции
&НаСервере
Функция ПортыЭлементаXDTO(ГрафСхемаXDTO,itemCode)Экспорт
	Данные=Новый Структура;
	Данные.Вставить("itemId",0);
	Данные.Вставить("port1x",0);
	Данные.Вставить("port1y",0);
	Данные.Вставить("port2x",0);
	Данные.Вставить("port2y",0);
	Данные.Вставить("port3x",0);
	Данные.Вставить("port3y",0);
	Данные.Вставить("port4x",0);
	Данные.Вставить("port4y",0);
	Для Каждого Элемент Из ГрафСхемаXDTO.item Цикл
		Если СокрЛП(НРег(Элемент.itemCode))=СокрЛП(НРег(itemCode)) Тогда
			Данные.Вставить("itemId",Элемент.itemId);
			Данные.Вставить("port1x",Элемент.rectLeft);
			Данные.Вставить("port1y",Элемент.rectTop+(Элемент.rectBottom-Элемент.rectTop)/2);
			Данные.Вставить("port2x",Элемент.rectLeft+(Элемент.rectRight-Элемент.rectLeft)/2);
			Данные.Вставить("port2y",Элемент.rectTop);
			Данные.Вставить("port3x",Элемент.rectRight);
			Данные.Вставить("port3y",Элемент.rectTop+(Элемент.rectBottom-Элемент.rectTop)/2);
			Данные.Вставить("port4x",Элемент.rectLeft+(Элемент.rectRight-Элемент.rectLeft)/2);
			Данные.Вставить("port4y",Элемент.rectBottom);
			Прервать;
		КонецЕсли;	  
	КонецЦикла;
	Возврат Данные;
КонецФункции
&НаСервере
Функция ИндексЭлементаXDTO(ГрафСхемаXDTO,itemCode)Экспорт
	Для Й=0 По ГрафСхемаXDTO.item.Количество()-1 Цикл
		Если СокрЛП(НРег(ГрафСхемаXDTO.item[Й].itemCode))=СокрЛП(НРег(itemCode)) Тогда
			Возврат Й;
		КонецЕсли;	  
	КонецЦикла;
	Возврат -1;
КонецФункции
&НаСервере
Функция НайтиЭлементXDTO(ГрафСхемаXDTO,itemCode)Экспорт
	Для Каждого Элемент Из ГрафСхемаXDTO.item Цикл
		Если СокрЛП(НРег(Элемент.itemCode))=СокрЛП(НРег(itemCode)) Тогда
			Возврат Элемент;
		КонецЕсли;	  
	КонецЦикла;
	Возврат Неопределено;
КонецФункции
&НаСервере
Процедура УдалитьЭлементXDTO(ГрафСхемаXDTO,itemCode)Экспорт
	ГрафСхемаXDTO.item.Удалить(ИндексЭлементаXDTO(ГрафСхемаXDTO,itemCode));
КонецПроцедуры
&НаСервере
Функция ПолучитьТекстЭлементаXDTO(ГрафСхемаXDTO,itemCode)Экспорт
	Элемент=НайтиЭлементXDTO(ГрафСхемаXDTO,itemCode);
	Возврат Элемент.itemTitle.item[0].content;
КонецФункции
&НаСервере
Процедура ИзменитьТекстЭлементаXDTO(ГрафСхемаXDTO,itemCode,НовыйТекст)Экспорт
	Элемент=НайтиЭлементXDTO(ГрафСхемаXDTO,itemCode);
	Элемент.itemTitle.item[0].content=НовыйТекст;
КонецПроцедуры


Показать


к сожалению работает не идеально , порты линий нужно проставить вручную , линии переходов иногда "склеиваются " , чтобы их разделить нужно немного "пошевелить " элемент
7. pm74 176 19.02.18 12:14 Сейчас в теме
(5)с графической схемой работать удобно , единственный минус(имо) - нет расшифровки , поэтому сделать полностью интеракивной (например как рис.) сложновато
Прикрепленные файлы:
8. Yashazz 3329 19.02.18 12:50 Сейчас в теме
В предложенной публикации порты управляются программно, их можно перевешивать как угодно. А что линии склеиваются, так это штатная манера самой 1С, для созданных вручную всё так же.
нет расшифровки

Это почему? Есть расшифровка, у меня часть бизнес-логики именно на ней основана. Очень даже есть.
9. pm74 176 19.02.18 12:57 Сейчас в теме
(8)
Есть расшифровка

интересненько , я пока внимательно не прочитал (имел в виду "родную" расшифровку как в ТД )
интерфейс наподобие обработки расшифровки тоже есть ?

(8)
управляются программно
т.е. есть алгоритм для "красивого" расположения входных и выходных портов ?
10. Yashazz 3329 19.02.18 17:49 Сейчас в теме
(9) Конечно есть. Роднее некуда. Собственно, это штатная возможность граф.схем, я ею пользовался, но ничего сверхъестественного не делал, чтобы она работала, она как раз и сама по себе в платформе очень даже.

Алгоритма нет, есть параметр, который этим управляет. Свойство с типом, как в платформе. Делать алгоритм для красоты, скажу честно, было тупо некогда)
11. pm74 176 19.02.18 19:43 Сейчас в теме
(10)
Собственно, это штатная возможность граф.схем, я ею пользовался, но ничего сверхъестественного не делал

Я и впрямь что-то упустил. (связанную с элементами ГС какую- то коллекцию-реквизит пока не рассматриваем) , вроде в ГС нет параметров из которых можно напрямую извлечь ссылку на объект базы данных.
Не могли бы пояснить , а то чего-то недопонимаю.
(10)
есть параметр, который этим управляет
это понятно , имел в виду вручную (либо по умолчанию) назначение номеров входов / выходов

Под "красивой" расстановкой подразумевалось полностью программное расположение элементов , обеспечивающее наилучшую компактность и читабельность схемы при наименьшем пересечении линий.
12. Serg O. 187 21.02.18 07:00 Сейчас в теме
Листинг на 5 стр. Зачем? Читать код тут...никто не будет.
Сами же пишете, что у Вас готовое для допила решение
13. Yashazz 3329 21.02.18 19:23 Сейчас в теме
(12) Читать не будут. Копипастить будут) Особенно те, у кого стартманей нету)) Читайте внимательнее: обработка - для допила, а код - уже боевой.
Зеленоград; XelOla; +2 Ответить
Оставьте свое сообщение

См. также

Установка предопределенных элементов: просмотр, исправление и поиск ошибок (задвоенных и отсутствующих) Промо

Инструментарий разработчика Универсальные обработки v8 1cv8.cf Абонемент ($m)

Простая обработка для просмотра и установки значений предопределенных элементов. Позволяет заменить значение предопределенного элемента с одного элемента справочника на другой, удалить предопределенный элемент (снять пометку предопределенности), установить пометку переопределенного элемента. Проверяет предопределенные данные на наличие задвоений и отсутствующих. Работает со справочниками, планами счетов, планами видов характеристик, планами видов расчетов.

2 стартмани

06.10.2014    147375    1973    ekaruk    164    

Альтернативный способ добавления элементов и реквизитов на формы

Работа с интерфейсом v8 ERP2 УТ11 Россия Абонемент ($m)

Предлагаю альтернативный вариант добавления динамически создаваемых элементов и реквизитов на форму.

1 стартмани

09.09.2019    9915    11    bmk74    2    

Модель объекта

Инструментарий разработчика v8 Абонемент ($m)

Подсистема позволяет описать модель данных объекта, где описана зависимость между реквизитами, и затем использовать эту модель в разных сценариях работы с объектом. Версия платформы: 8.3.6 и выше. С небольшими доработками будет работать на 8.2.

1 стартмани

30.06.2019    11608    0    vadim1980    5    

Редактор объектов информационной базы 8.3

Универсальные обработки Обмен через XML v8 v8::УФ 1cv8.cf Россия Абонемент ($m)

Универсальная внешняя обработка для редактирования реквизитов и табличных частей объектов информационной базы, редактирование движений документов. Доступ ко всем реквизитам объектов, есть возможность выгрузки и загрузки данных (объекты и движения документов) через XML. Платформа 8.3, управляемые формы. Версия 1.1.0.49 от 05.08.2020

2 стартмани

23.01.2019    26856    276    ROL32    36    

Навигатор по конфигурации базы 1С 8.3 Промо

Инструментарий разработчика Универсальные обработки v8 v8::УФ 1cv8.cf Россия Абонемент ($m)

Универсальная внешняя обработка для просмотра метаданных конфигураций баз 1С 8.3. Отображает свойства и реквизиты объектов конфигурации, их количество, основные права доступа и т.д. Отображаемые характеристики объектов: свойства, реквизиты, стандартные рекизиты, реквизиты табличных частей, предопределенные данные, регистраторы для регистров, движения для документов, команды, чужие команды, подписки на события, подсистемы. Отображает структуру хранения объектов базы данных, для регистров доступен сервис "Управление итогами". Платформа 8.3, управляемые формы. Версия 1.1.0.65 от 05.08.2020

3 стартмани

28.10.2018    31641    283    ROL32    67    

Конструктор мобильного клиента Simple WMS Client: способ создать полноценный ТСД без мобильной разработки. Теперь новая версия - Simple UI (обновлено 14.11.2019)

Инструментарий разработчика Сканер штрих-кода Терминал сбора данных Мобильная разработка Оптовая торговля Производство готовой продукции (работ, услуг) Розничная торговля Учет ОС и НМА Учет ТМЦ Оптовая торговля Производство готовой продукции (работ, услуг) Розничная торговля Учет ОС и НМА Учет ТМЦ v8 v8::Mobile БУ УУ Абонемент ($m)

Simple WMS Client – это визуальный конструктор мобильного клиента для терминала сбора данных(ТСД) или обычного телефона на Android. Приложение работает в онлайн режиме через интернет или WI-FI, постоянно общаясь с базой посредством http-запросов (вариант для 1С-клиента общается с 1С напрямую как обычный клиент). Можно создавать любые конфигурации мобильного клиента с помощью конструктора и обработчиков на языке 1С (НЕ мобильная платформа). Вся логика приложения и интеграции содержится в обработчиках на стороне 1С. Это очень простой способ создать и развернуть клиентскую часть для WMS системы или для любой другой конфигурации 1С (УТ, УПП, ERP, самописной) с минимумом программирования. Например, можно добавить в учетную систему адресное хранение, учет оборудования и любые другие задачи. Приложение умеет работать не только со штрих-кодами, но и с распознаванием голоса от Google. Это бесплатная и открытая система, не требующая обучения, с возможностью быстро получить результат.

5 стартмани

09.01.2019    42017    247    informa1555    230    

Сравнение pdf-файлов актов сверки

Универсальные обработки Дебиторская и кредиторская задолженность Дебиторская и кредиторская задолженность v8 v8::БУ БП2.0 Россия БУ Абонемент ($m)

Обработка сравнивает два pdf-файла, в которых находятся стандартные печатные формы актов сверки, и показывает на экране совпадающие и/или отличающиеся по суммам документы взаиморасчетов.

1 стартмани

19.12.2018    16318    9    Torin99    2    

Выгрузка изображений из справочника на диск

Учет ТМЦ Универсальные обработки Учет ТМЦ v8 УТ11 Оптовая торговля, дистрибуция, логистика Россия Абонемент ($m)

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

1 стартмани

30.11.2018    16224    6    wrooom    8    

Универсальная выгрузка/загрузка данных для отличающихся конфигураций (JSON, Такси+ОФ) Промо

Перенос данных из 1C8 в 1C8 Универсальные обработки Распределенная БД (УРИБ, УРБД) v8 1cv8.cf Абонемент ($m)

Простой перенос через JSON данных между двумя базами 1С (документов, справочников, ПВХ, ПВР, счетов). Аналогична произвольной выгрузке в типовой "Выгрузка/загрузка XML", но может использоваться для отличающихся конфигураций. Подходит для любых пар баз с любым интерфейсом (управляемый + обычный). Без настроек. Не требует идентичности конфигураций и платформ. При переносе типы данных сопоставляются по наименованиям метаданных, объекты и ссылки по UID.

1 стартмани

22.10.2014    204140    3097    ekaruk    180    

Обнуление остатков регистров бухгалтерии и накопления

Универсальные обработки Чистка базы v8 v8::БУ v8::ОУ v8::УФ КА1 БП2.0 ЗУП2.5 УТ10 УПП1 УНФ БГУ ERP2 БП3.0 УТ11 УХ КА2 ЗУП3.x Россия Абонемент ($m)

Обработка позволяет обнулить остатки по регистру накопления или бухгалтерии на определенную дату. Поддерживается большинство типовых конфигураций (БП 3, БП 2, УТ 11, УТ 10, ЗУП 3, ЗУП 2, БГУ 2, БГУ 1, ERP, УПП, КА 2, КА 1, УХ 3, УХ 1, УНФ). Гибкая настройка (отборы, заполнение реквизитов и любых полей корр. счета, возможность обнулять ресурсы выборочно). Несколько режимов работы. Два интерфейса: простой и с расширенным набором настроек.

2 стартмани

19.11.2018    21081    278    morozov.sv    50    

Открывашка ячеек таблиц

Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Глобальное сочетание клавиш для открытия объекта по ссылке из текущей ячейки любой таблицы в большинстве управляемых форм

1 стартмани

27.10.2018    15940    12    tormozit    31    

Универсальный инструмент для переноса данных через табличный документ (УФ)

Обработка документов Универсальные обработки Обработка справочников v8 v8::УФ 1cv8.cf Абонемент ($m)

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

5 стартмани

15.10.2018    31554    115    json    36    

[Расширение] Контроль отрицательных остатков по регистру бухгалтерии при проведении Промо

Универсальные функции Инструментарий разработчика Учет ТМЦ Учет ТМЦ v8 1cv8.cf Россия БУ Абонемент ($m)

Расширение позволяет без изменений конфигурации проверять остатки по регистру бухгалтерии при проведении каждого документа и запрещает проведение при появлении отрицательных остатков после проведения.

1 стартмани

17.08.2015    45851    155    ekaruk    32    

Позиционирование в помещении с помощью нейросети по сигналу Wi-Fi. Интерактивная карта склада в 1С с показом позиции

Инструментарий разработчика Практика программирования v8 Абонемент ($m)

Данная публикация содержит в себе редактор и интерактивную карту склада или иного помещения, на которой в реальном времени отображается позиция устройства, координаты которого вычисляются по уровням сигнала нескольких роутеров Wi-Fi. В статье и приложенным к ней разработкам предлагаются инструменты и методика для реализации вычисления точной геопозиции внутри помещений с помощью нейронной сети. Конфигурация написана на релизе 1С:Предприятие 8.3.12.1412, клиентское приложение имеет минимальный уровень совместимости SDK -16.

5 стартмани

09.08.2018    26352    26    informa1555    26    

Визуализация событий на временной шкале средствами "Поле HTML документа"

Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Интересный способ наглядно отобразить события на временной шкале. Например, может быть применен для красивого вывода документов по клиенту. Тестировалось на платформе 8.3.12.1469

1 стартмани

31.07.2018    22519    137    Plotks2017    27    

Работа с данными выбора

Практика программирования Работа с интерфейсом v8 Россия Абонемент ($m)

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

1 стартмани

17.07.2018    42655    17    kalyaka    16    

Faster - многофункциональный ускоритель работы программиста 1С Промо

Инструментарий разработчика v8 1cv8.cf Россия Абонемент ($m)

Программа Faster 8.7 позволяет ускорить процесс работы программиста 1С (и не только 1C). Программа Faster позволяет делится кодом с другими программистами в два клика или передать ссылку через QR Код. Исправление введенных фраз двойным Shift (с помощью speller.yandex) Полезная утилита для тех, кто печатает много однотипного текста, кодирует в среде Windows на разных языках программирования. Через некоторое время работы с программой у вас соберется своя база часто используемых словосочетаний и кусков кода. Полностью переделан механизм перехвата клавиш, теперь не зависает при обработке скриптов.

1 стартмани

24.05.2012    76441    207    moolex    145    

Просмотр, изменение реквизитов объекта. Сравнение двух одинаковых объектов метаданных ИБ

Универсальные обработки v8 1cv8.cf Россия Абонемент ($m)

Показывает реквизиты объекта (ов) или сравнивает два одинаковых объекта конфигурации справочники, документы.

1 стартмани

26.04.2018    17375    24    Vin_Tik    0    

Регистры правил [Расширение]

Инструментарий разработчика Информационная безопасность v8 v8::Права УТ11 Абонемент ($m)

Регистры правил - права доступа, запрет редактирования, автоподстановка реквизитов и т.д.

10 стартмани

15.03.2018    16788    9    33lab    1    

Построение маршрута доставки с расчётом расстояния для любой базы УФ

Универсальные обработки WEB Оптовая торговля Оптовая торговля v8 v8::УФ 1cv8.cf Абонемент ($m)

Графическое изображение маршрутного листа по картам гугл. Работает на любой конфигурации с управляемыми формами. Использует новую версию api google-карт от 13.02.2018 года под IE11.

10 стартмани

24.02.2018    33888    42    KorotkovRV    16    

Перемещение остатков по счету МЦ04 между материально ответственными лицами для конфигураций (8.2). Промо

Обработка документов Универсальные обработки Учет ТМЦ Учет ТМЦ v8 БП2.0 Россия БУ Абонемент ($m)

Небольшая обработка, которая позволяет перекидывать остатки по счету МЦ04 с одного материально ответственного лица на другое

1 стартмани

22.11.2012    13552    13    niksaf    4    

Программное формирование форматированной строки в стиле html+inline CSS

Работа с интерфейсом Инструментарий разработчика v8 1cv8.cf Абонемент ($m)

Если вам приходилось работать с форматированными строками программно, то вы знаете, какая это боль. Данное решение облегчает программное формирование таких строк.

1 стартмани

18.11.2017    29623    32    bonv    10    

Инструменты бухгалтера: Виджеты рабочего стола

Универсальные обработки Рабочее место v8 v8::БУ БП3.0 Абонемент ($m)

Настраиваемые виджеты на начальной странице, своеобразная панель для быстрого доступа к объектам. Виджеты это элементы интерфейса в виде цветных прямоугольников со ссылками на объекты конфигурации. Использование виджетов позволяет сконцентрировать на начальной странице часто используемые функции, например, варианты отчетов, списки документов, или используя виджет вводить новый документ прямо из начальной страницы.

2 стартмани

28.08.2017    36203    170    Bazil    28    

Расширенная настройка динамического списка УФ

Работа с интерфейсом v8 v8::УФ 1cv8.cf Абонемент ($m)

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

1 стартмани

31.05.2017    30858    147    tormozit    23    

Консоль запросов + ТЗ как параметры Промо

Консоль запросов v8 1cv8.cf Украина Абонемент ($m)

Стандартная консоль запросов, с добавленной возможностью использования описания/заполнения/использования таблиц значений как параметров. Совместима с настройками базовой консоли. Упрощает отладку запросов, использующих временные таблицы.

2 стартмани

12.11.2010    33712    60    Kashemir    24    

Набор подсистем "Умные таблицы"

Инструментарий разработчика v8 Беларусь Россия Казахстан Абонемент ($m)

Данный набор подсистем – прикладная библиотека, призванная помочь программисту 1С быстрее решать ряд типовых задач бизнес-логики, таких как: ведение статусов объектов, отправка почтовых сообщений в определенное время, ведение произвольных таблиц с возможностью редактирования, сохранения и группировки, ориентированные на расчет бюджетных таблиц (план продаж, ретробонусы B2C, проценты по договорам B2B и договорные условия по КАМ), расчет коммерческой политики для бюджетных таблиц, исполнение произвольных алгоритмов с хранением кода в информационной базе, определение рабочих баз, хранение файлов во внешних СУБД (Postgre SQL, MS SQL и MongoDB) и выполнение произвольного кода после изменений ссылочного объекта вне транзакции изменения.

1 стартмани

22.05.2017    31813    94    Silenser    34    

Программное создание графических схем (v.2): API для ГрафическойСхемы

Практика программирования Работа с интерфейсом Универсальные функции v8 Бесплатно (free)

Пример динамического создания графических схем, добавления элементов любых видов. Любые схемы без бизнес-процессов. Программная работа со схемой. Отличие от существующей статьи в том, что здесь используется объектная модель. Исправил и упростил некоторые моменты - результат соответствует схеме, созданной руками. Добавил возможность рисования произвольных форм для существующих фигур.

27.09.2016    19800    serg_infostart    18    

Поиск и отключение зависших сеансов на сервере 1С: Предприятия

Универсальные обработки v8 1cv8.cf Россия Абонемент ($m)

Обработка предназначена для мониторинга и отключения спящих (зависших) сеансов на сервере 1С: Предприятия.

1 стартмани

14.09.2016    30992    61    wowchik_85    11    

[x1c.ru] 1CDBin: Работа с файлами *.1CD на низком уровне средствами языка 1С с возможностью чтения таблиц (поддерживается формат 8.3.8.0) Промо

Тестирование и исправление Инструментарий разработчика v8 1cv8.cf Абонемент ($m)

Обработка позволяет просматривать файловые базы 1CD на низком уровне средствами встроенного языка. Реализована часть функциональности Tool_1CD, но на языке 1С Предприятия. Показываются таблицы, параметры таблиц, поля таблиц, записи таблиц, значения полей BLOB, есть 16-ричный просмотр страниц базы и консоль кода. Можно использовать для изучения структуры файлов 1CD, просмотра баз 1CD для выявления повреждений, создания своих обработок для выгрузки данных без открытия исследуемой базы в 1С:Предприятии.

1 стартмани

07.10.2014    50961    207    GusevNA    75    

Редактор движений документа. Сохранение в XML, обмен между базами, замена регистратора.

Обработка документов Универсальные обработки Обмен через XML v8 Абонемент ($m)

Редактор набора записей движений документа. Позволяет сохранить набор записей в XML, в настройки пользователя, прочитать сохраненный XML в другой идентичной базе, заменить регистратор. Можно изменять порядок записей, менять активность, как массово, так и по одной и др. Тонкий клиент, управляемые формы.

1 стартмани

07.09.2016    39872    155    Aphanas    4    

Универсальный поиск объектов по глобальному уникальному идентификатору (ГУИД, GUID)

Универсальные обработки Поиск данных v8 v8::УФ 1cv8.cf Абонемент ($m)

Универсальная обработка поиска объектов информационной базы по глобальному уникальному идентификатору (ГУИД, GUID) или по его части.

1 стартмани

06.09.2016    31905    103    Dzenn    9    

Конструктор-тестер http запросов в 1С

WEB Инструментарий разработчика v8 1cv8.cf Россия Абонемент ($m)

Данная обработка позволяет в несколько кликов конструировать http запросы на языке 1С и просматривать результаты их выполнения.

3 стартмани

19.08.2016    40910    295    hlopik    17    

Оптимальный способ расчета контрольной суммы объекта/записи регистра (CRC32, MD5, SHA1, SHA256)

Универсальные обработки v8 1cv8.cf Абонемент ($m)

Была задача сравнить документы в распределенных базах и пометить на выгрузку измененные. Но сравнение изменений документов методом перебора реквизитов - долгоиграющий процесс, особенно если общее количество сравниваемых данных переваливает за миллион. Был найден выход, который ускоряет процесс сравнения - расчет контрольной суммы объекта и сравнение ее с другой контрольной суммой. Скорость сравнения увеличивается во много раз.

1 стартмани

01.08.2016    30310    6    hakerxp    9    

Подсистема обмена данными с порталом ИМНС по электронным счетам-фактурам (автоматический обмен)

Внешние источники данных WEB Инструментарий разработчика v8 1cv8.cf Беларусь БУ НДС Абонемент ($m)

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

1 стартмани

28.07.2016    32447    19    c1nil    4    

Навигатор по структуре и данным баз 1С 8

Инструментарий разработчика v8 v8::УФ 1cv8.cf Абонемент ($m)

Просмотр структуры и данных информационных баз 1С:Предприятие 8.2, 8.3. Состав, типы объектов, табличных частей, движений. Размер, структура хранения объекта. Для администраторов и разработчиков. Версия 1 - на обычных формах, версия 2 - на управляемых.

1 стартмани

11.07.2016    27853    127    o.nikolaev    17    

Консоль запросов "Запросник" для управляемых форм с подсветкой синтаксиса

Консоль запросов v8 1cv8.cf Абонемент ($m)

Вот уже много лет я использую замечательный инструмент для работы с запросами - Запросник. Однако, с переходом на управляемые формы для его использования пришлось запускать базы в устаревшем толстом клиенте, да еще и разрешать в свойствах конфигурации использование обычных форм. В 2014 году появился запросник на управляемых формах, который, к сожалению, оказался несовершенен из за ограничений платформы. Самое неприятное из них - отсутствие подсветки синтаксиса. Мне кажется, что я нашел решение этой проблемы.

1 стартмани

19.04.2016    36272    256    1С_Мастер    42    

Просмотр данных системы Платон на картах Google

Универсальные обработки WEB v8 1cv8.cf Автомобили, автосервисы Транспорт, автопарки, такси Абонемент ($m)

Обработка для просмотра предполагаемых треков движения транспортного средства на карте Google согласно данным, предоставляемым системой Платон в формате CSV. Работает под 8.2 и 8.3, обычное и управляемое приложение, может подключаться к типовым конфигурациям в качестве внешней обработки.

1 стартмани

15.04.2016    31516    18    anig99    8    

Простые радости жизни программиста 1С: выбор типа значения

Работа с интерфейсом Практика программирования v8 1cv8.cf Абонемент ($m)

Предлагаемая в работе обработка включает обычную и управляемую формы, которые максимально точно реализуют функциональность системного диалога выбора типа в толстом клиенте обычное приложение (включая оформление диалога). Эти формы имеют дополнительные интерфейсные удобства и могут быть использованы в качестве альтернативных диалогов выбора типа.

1 стартмани

17.02.2016    47729    50    yuraos    17    

Яндекс.Деньги "Благотворительность"

Инструментарий разработчика Практика программирования v8 1cv8.cf Абонемент ($m)

Яндекс.Деньги теперь в 1С. Форма для приема благотворительных взносов. Форму легко сделать и вставить на любую страницу сайта или блога. Платежи будут приходить на ваш кошелек. На форме есть три способа платежа: из кошелька, с банковской карты, с баланса мобильного.

1 стартмани

16.02.2016    22110    8    Tatitutu    5    

ЕГАИС: код алкогольной продукции из штрихкода акцизной марки

Универсальные обработки Оптовая торговля Розничная торговля Оптовая торговля Розничная торговля v8 1cv8.cf Розничная и сетевая торговля (FMCG) Оптовая торговля, дистрибуция, логистика Акцизы Абонемент ($m)

В последнее время мне пришлось потратить очень много времени на внедрение и реализацию функционала ЕГАИС. Очень часто, на форумах, я встречал вопрос: "Как из штрих-кода акцизной марки получить код алкогольной продукции ЕГАИС?". Несколько раз видел неверную реализацию этой задачи. Глядя на это, я набросал простую обработку пересчета кода акцизной марки (base36) в понятный нам уникальный ФСРАР ID алкогольной продукции (Base10).

1 стартмани

11.02.2016    55663    156    OrcaMax    29    

Снимок экрана для 1С

Универсальные обработки Разработка внешних компонент v8 1cv8.cf Россия Абонемент ($m)

Довольно часто люди сталкиваются с необходимостью сделать снимок экрана. Если вы или ваши сотрудники основную часть времени проводят в 1С и у вас есть необходимость прикреплять графические файлы, то эта компонента для вас.

1 стартмани

08.02.2016    26851    33    linkforget    11    

Генерация QR-кода программная и интерактивная (код открыт, управляемая форма, обычное и управляемое приложение, API)

Универсальные функции Универсальные обработки v8 v8::УФ 1cv8.cf Абонемент ($m)

Обработку можно быстро и легко интегрировать в любую конфигурацию с и без БСП (Библиотека Стандартных Подсистем).

3 стартмани

04.02.2016    46303    172    TuneSoft    26    

Интерфейс сопоставления объектов для обмена (для типового регистра СоответствиеОбъектовДляОбмена)

Инструментарий разработчика Универсальные обработки Перенос данных из 1C8 в 1C8 v8 КА1 БП2.0 ЗУП2.5 УТ10 УПП1 Абонемент ($m)

Вы внедряете обмен данными между двумя типовыми или основанными на типовых БД и вам необходим инструмент, чтобы сопоставить между собой справочники этих конфигураций? Вы хотите навести порядок в обмене данными, потому что вам надоело вылавливать дублирующиеся объекты? Вам очень хочется перепоручить сопоставление объектов обменивающихся баз пользователям, но нет подходящего и понятного пользователям интерфейса? Тогда вам нужна именно эта обработка!

4 стартмани

11.11.2015    38127    133    catsam    8    

Exec - Выполнение кода, консоль запросов и не только!

Консоль запросов v8 1cv8.cf Абонемент ($m)

Незаменимый инструмент администратора БД и программиста: Выполняйте произвольный код из режима 1С Предприятие; сохраняйте/загружайте часто используемые скрипты; выполняйте запросы с замером производительности запроса в целом и каждой из временных таблиц в частности, а также с просмотром содержимого временных таблиц; произвольным образом изменяйте любые объекты БД, редактируя даже не вынесенные на формы реквизиты и записывая изменения в режиме "ОбменДанными.Загрузка = Истина"; легко узнавайте ИД объектов БД; выполняйте прямые запросы к SQL с замером производительности и не только!

5 стартмани

10.11.2015    39846    75    catsam    11    

[x1c.ru] MXL Stamps - Печати и подписи в макетах печатных форм в несколько кликов

Печатные формы документов Универсальные обработки v8 1cv8.cf Абонемент ($m)

Обработка позволяет быстро создавать поля текста из ячеек печатных форм и добавлять "под них" подписи и печати. Работает в конфигурациях на управляемых формах.

1 стартмани

22.08.2015    35405    18    GusevNA    6    

Работа с push сервисами только средствами 1С 8.2

Сервисные утилиты Инструментарий разработчика Универсальные обработки v8 Абонемент ($m)

Обработка для настройки, тестирования и использования с предустановками для 3-х сервисов. Текст модуля для внедрения в конфигурацию или другие обработки. Уведомления на телефон, компьютер, браузер.

1 стартмани

18.08.2015    29778    43    anig99    1