Использование значений серий и точек

В данном разделе рассматриваются особенности заполнения данными объектов Диаграмма и ДиаграммаГанта с использованием ключевых значений.

Диаграмма

Для того чтобы задать значение диаграммы для пары (серия, точка), существует метод УстановитьЗначение(<Точка>, <Серия>, <Значение>, <Расшифровка>), где в качестве параметров <Точка> и <Серия> могут выступать или индексы, или значения типов ТочкаДиаграммы и СерияДиаграммы соответственно. Вопрос заключается в том, что при обходе источника данных бывает сложно для конкретного значения определить соответствующую ему серию или точку.

Существуют три пути решения этой проблемы. 

Первый вариант - мы должны свести обход источника данных к примерно такой конструкции:

Копировать в буфер обмена

Цикл обхода по всем значениям серий 
    Цикл обхода по всем значениям точек 
    КонецЦикла 
КонецЦикла

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

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

Рассмотрим третий вариант - использование свойств Значение объектов ТочкаДиаграммы и СерияДиаграммы и методов объекта Диаграмма УстановитьСерию(<Значение>) и УстановитьТочку(<Значение>), где в качестве параметра может выступать значение произвольного типа. Эти методы работают следующим образом. Среди существующих серий (точек) ищется серия со свойством Значение, равным значению параметра. Если такая серия находится, то она возвращается, иначе создается и возвращается новая. Для созданной серии свойство Значение устанавливается равным переданному параметру.

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

Копировать в буфер обмена
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	ТоварыОстатки.КоличествоОстаток КАК Количество,
|	ТоварыОстатки.Товар КАК Товар,
|	ТоварыОстатки.Склад КАК Склад 
|ИЗ
|	РегистрНакопления.Товары.Остатки КАК ТоварыОстатки"; 
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать(); 

		// Заполнение диаграммы.

Диаграмма = ЭлементыФормы.Диаграмма1;
Диаграмма.Обновление = Ложь;
Диаграмма.Очистить();

Пока Выборка.Следующий() = Истина Цикл
	Серия = Диаграмма.УстановитьСерию(Выборка.Товар);
	Точка = Диаграмма.УстановитьТочку(Выборка.Склад);
	Диаграмма.УстановитьЗначение(Точка, Серия, Выборка.Количество);
КонецЦикла;

Диаграмма.Обновление = Истина;

Рассмотрим вопрос с уникальностью значений. При "стандартном" способе использования свойства Значение, подобном описанному выше, у каждой серии будет уникальное (в пределах всех серий) значение (оно может быть и пустым). Однако можно заполнять диаграмму, используя разные способы - метод УстановитьСерию() для одних серий и другие возможности (свойство КоличествоСерий у диаграммы, метод Добавить() у коллекции серий) для других. В этом случае возможна ситуация, когда у нескольких серий будет одинаковое значение. Как в этом случае будет работать метод УстановитьСерию()? Он вернет первую (с наименьшим индексом) из подходящих. Но хотя подобное поведение документировано, рекомендуется заполнять диаграмму, используя какой-то один способ.

Свойство Значение у серий и точек диаграммы может использоваться не только для получения по некоторому ключу. Если у соответствующей серии не установлено свойство Текст, то для вывода подписи будет использоваться строковое представление значения. Стоит обратить внимание на одну тонкость. У диаграммы есть свойство АвтоУстановкаТекстаСерий, причем по умолчанию это свойство включено. В этом случае для каждой вновь созданной серии будет генерироваться текст вида "Серия1". Но если серия добавляется через метод УстановитьСерию(), то независимо от значения свойства АвтоУстановкаТекстаСерий текст генерироваться не будет.

Диаграмма Ганта

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

Соответствующий метод получения серии по ключевому значению выглядит следующим образом: УстановитьСерию(<Значение>, <ЗначениеРодителя>). Алгоритм его действия следующий. Если среди существующих серий найдена серия со значением, равным <Значение>, то она возвращается независимо от значения параметра <ЗначениеРодителя>, поскольку уникальность значения, как и в случае обычной диаграммы, подразумевается среди всех серий, а не только среди серий, подчиненных одному родителю. Если подходящую серию найти не удалось, то ищется серия со значением, равным <ЗначениеРодителя>. Если такая серия найдена, то новая серия создается среди ее подчиненных, иначе - на верхнем уровне. То есть серия со значением <ЗначениеРодителя> автоматически не создается (так как не определено, на каком уровне ее создавать). Это накладывает ограничения на порядок обхода источника данных (конечно, если в реальных данных действительно присутствует иерархия). Первое обращение к любой серии должно происходить после первого обращения к ее родителю, в противном случае иерархия будет нарушена. В случае запроса это требует использования итогов по иерархии, а также дополнительных проверок в коде обхода результата. Следующий пример обхода может использоваться как образец.

Копировать в буфер обмена
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	ПланыРабот.ВидПлана КАК ВидПлана,
|	ПланыРабот.Работа КАК Работа,
|	ПланыРабот.Начало,
|	ПланыРабот.Окончание,
|	ПланыРабот.ВидПлана.Родитель КАК РодительПлана,
|	ПланыРабот.Работа.Родитель КАК РодительРаботы
|ИЗ
|	Справочник.ПланыРабот КАК ПланыРабот
|
|УПОРЯДОЧИТЬ ПО
|	ПланыРабот.Работа.Код
|
|ИТОГИ ПО
|	Работа ТОЛЬКО ИЕРАРХИЯ,
|	ВидПлана ТОЛЬКО ИЕРАРХИЯ";

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

		// Заполнение диаграммы Ганта.

Диаграмма = ЭлементыФормы.ДиаграммаГанта1;
Диаграмма.Обновление = Ложь;
Диаграмма.Очистить();

Пока Выборка.Следующий() = Истина Цикл
	Если Выборка.Работа <> Null И Не Выборка.Работа.Пустая() Тогда
		Точка = Диаграмма.УстановитьТочку(Выборка.Работа,
		                                  ?(Выборка.Работа.Пустая() Или Выборка.РодительРаботы.Пустая(),
						    Неопределено, Выборка.РодительРаботы));
	КонецЕсли;

	Если Выборка.ВидПлана <> Null И Не Выборка.ВидПлана.Пустая() Тогда
		Серия = Диаграмма.УстановитьСерию(Выборка.ВидПлана,
		                                  ?(Выборка.ВидПлана.Пустая() Или Выборка.РодительПлана.Пустая(),
						    Неопределено, Выборка.РодительПлана));
	КонецЕсли;

	Если Выборка.Начало <> Null Тогда
		Значение = Диаграмма.ПолучитьЗначение(Точка, Серия);
		Интервал = Значение.Добавить();
		Интервал.Начало = Выборка.Начало;
		Интервал.Конец = Выборка.Окончание;
	КонецЕсли;

КонецЦикла;

Диаграмма.Обновление = Истина;

Иерархическая структура серий и точек ведет к еще одной особенности диаграммы Ганта по сравнению с обычной диаграммой. Выше было описано поведение метода УстановитьСерию() в случае наличия серий с одинаковыми значениями. У диаграммы он возвращает подходящую серию с наименьшим индексом. У диаграммы Ганта также возвращается подходящая серия, но какая именно - не определено, что является еще одним аргументом в пользу одновременного использования только одного способа заполнения диаграммы.