Каждый разработчик, столкнувшийся с задачей построения графиков и диаграмм в платформе «1С:Предприятие 7.7», рано или поздно натыкается на суровую реальность визуализации данных этой эпохи. Встроенные механизмы платформы обладают жесткими архитектурными ограничениями, способными превратить любой красивый отчет в хаотичное нагромождение цветов.
Типичная проблема выглядит следующим образом: мы строим гистограмму продаж по производителям (серии) за несколько месяцев (точки). В одном месяце лидером продаж является «Производитель А», а в другом — «Производитель Б». Из-за изменения сортировки (ранжирования лидеров) штатный механизм диаграммы 1С 7.7 автоматически переназначает цвета. В результате один и тот же производитель в январе отображается синим столбцом, в феврале — зеленым, а в марте — красным. Читать такой отчет становится невозможно.
В этой статье мы подробно разберем причины такого поведения платформы, выясним математику «округления» цветов и рассмотрим сразу несколько практических решений: от чистого кода на 1С до использования внешних компонент и ActiveX-технологий.
Давайте проанализируем ситуацию изнутри. Почему мы не можем просто передать случайные RGB-значения и получить красивый градиент? Дело в том, что штатные объекты 1С 7.7 (включая ячейки табличных документов и встроенный объект Диаграмма) не поддерживают полноценный 24-битный TrueColor напрямую.
Платформа использует фиксированную палитру из 56 стандартных цветов, которая полностью идентична палитре устаревших версий MS Office (в частности, палитре Excel 97-2003). Когда мы программно вызываем метод Диаграмма.ЦветСерии(НомерСерии, R, G, B) и передаем туда произвольные координаты RGB, платформа не выдает ошибку. Вместо этого она выполняет автоматическое округление.
Алгоритм приведения цвета вычисляет минимальную евклидову дистанцию между переданным нами цветом и всеми 56 эталонными цветами из своей палитры по формуле:
d = Sqrt((R1-R2)^2 + (G1-G2)^2 + (B1-B2)^2)
В результате ваш изысканный пастельный оттенок автоматически заменяется на ближайший «грязный» или ядовито-яркий стандартный цвет. Именно поэтому попытка сделать плавный градиент «в лоб» приводит к тому, что на диаграмме выводятся одинаковые, повторяющиеся цвета.
Еще одно ограничение — объектная модель 1С 7.7 работает только в режиме «записи». Мы можем установить цвет серии методом ЦветСерии(), но мы не можем прочитать текущий цвет серии, который платформа назначила автоматически. Метод-геттер для цвета в объекте Диаграмма попросту отсутствует.
Если мы хотим остаться в рамках штатных средств платформы без подключения сторонних библиотек, нам придется полностью взять управление палитрой на себя. Чтобы цвета производителей не «прыгали» от месяца к месяцу, мы должны использовать принудительное окрашивание серий.
Давайте разберем по шагам алгоритм реализации этого подхода:
0. Это гарантирует, что порядок серий на графике не изменится, а производитель сохранит свой цвет на протяжении всей временной оси.Посмотрим на пример реализации данного алгоритма в коде:
// Создаем Таблицу значений для хранения соответствия Производитель - Цвет
ТЗ_Цветов = СоздатьОбъект("ТаблицаЗначений");
ТЗ_Цветов.НоваяКолонка("Производитель", "Справочник.Контрагенты");
ТЗ_Цветов.НоваяКолонка("R", "Число", 3, 0);
ТЗ_Цветов.НоваяКолонка("G", "Число", 3, 0);
ТЗ_Цветов.НоваяКолонка("B", "Число", 3, 0);
// Заполняем список доступных контрастных цветов из штатной палитры 1С
// Ниже приведены примеры RGB-кодов из стандартных 56 цветов
Процедура ДобавитьЦветВПалитру(РегТЗ, Р, Г, Б)
РегТЗ.НоваяСтрока();
РегТЗ.R = Р; РегТЗ.G = Г; РегТЗ.B = Б;
КонецПроцедуры
// Инициализируем палитру
Палитра = СоздатьОбъект("ТаблицаЗначений");
Палитра.НоваяКолонка("R", "Число");
Палитра.НоваяКолонка("G", "Число");
Палитра.НоваяКолонка("B", "Число");
ДобавитьЦветВПалитру(Палитра, 255, 0, 0); // Красный
ДобавитьЦветВПалитру(Палитра, 0, 0, 255); // Синий
ДобавитьЦветВПалитру(Палитра, 0, 255, 0); // Зеленый
ДобавитьЦветВПалитру(Палитра, 255, 255, 0); // Желтый
ДобавитьЦветВПалитру(Палитра, 255, 0, 255); // Пурпурный
ДобавитьЦветВПалитру(Палитра, 0, 255, 255); // Циан
ДобавитьЦветВПалитру(Палитра, 128, 0, 0); // Бордовый
ДобавитьЦветВПалитру(Палитра, 0, 128, 128); // Темно-зеленый
// Назначаем цвета производителям
НомЦвета = 1;
ВыборкаПроизводителей.ВыбратьСтроки();
Пока ВыборкаПроизводителей.ПолучитьСтроку() = 1 Цикл
ТЗ_Цветов.НоваяСтрока();
ТЗ_Цветов.Производитель = ВыборкаПроизводителей.Производитель;
// Получаем цвет из палитры по кругу
Палитра.ПолучитьСтрокуПоНомеру(НомЦвета);
ТЗ_Цветов.R = Палитра.R;
ТЗ_Цветов.G = Палитра.G;
ТЗ_Цветов.B = Палитра.B;
НомЦвета = НомЦвета + 1;
Если НомЦвета > Палитра.КоличествоСтрок() Тогда
НомЦвета = 1;
КонецЕсли;
КонецЦикла;
// При заполнении диаграммы программно красим каждую серию
Диаграмма.КоличествоСерий(ТЗ_Цветов.КоличествоСтрок());
Для НомСерии = 1 По ТЗ_Цветов.КоличествоСтрок() Цикл
ТЗ_Цветов.ПолучитьСтрокуПоНомеру(НомСерии);
Диаграмма.ЦветСерии(НомСерии, ТЗ_Цветов.R, ТЗ_Цветов.G, ТЗ_Цветов.B);
Диаграмма.УстановитьИмяСерии(НомСерии, СокрЛП(ТЗ_Цветов.Производитель.Наименование));
КонецЦикла;
Этот способ гарантирует, что каждый производитель всегда будет окрашен в свой цвет, независимо от его места в рейтинге продаж за конкретный месяц.
Если ваша задача состоит не только в построении диаграммы, но и в выводе под ней расшифровки в виде таблицы (где строки должны строго соответствовать цветам столбцов диаграммы), стандартных возможностей работы с цветом ячеек вам может не хватить. Для обхода этого ограничения отлично подходит внешняя компонента tabledoc.dll.
С ее помощью можно задействовать расширенную палитру (до 256 цветов) в табличных документах 1С 7.7. Давайте посмотрим на пример кода, который позволяет вывести все доступные расширенные цвета и их штатные аналоги:
Процедура Сформировать()
// Загружаем внешнюю компоненту для расширенной работы с таблицами
Если ЗагрузитьВнешнююКомпоненту("tabledoc.dll") = 0 Тогда
Предупреждение("Не удалось загрузить tabledoc.dll!");
Возврат;
КонецЕсли;
Таб = СоздатьОбъект("Таблица");
Менеджер = СоздатьОбъект("МенеджерТабличногоДокумента");
Менеджер.УстановитьТаблицу(Таб);
Для Стр = 1 По 32 Цикл
Для Кол = 1 По 8 Цикл
Индекс = (Стр-1) * 8 + (Кол-1);
// К штатной палитре относятся только цвета с индексами 0..55
// Остальные - расширенные. Установка их штатным способом
// приводит к округлению до ближайшего стандартного цвета.
// Расширенная палитра - 256 цветов
РасшОбласть = Менеджер.Область(Стр, Кол);
РасшОбласть.ЦветФонаПоИндексу(Индекс);
РасшЦвет = РасшОбласть.ЦветФона();
РасшОбласть.Текст = РасшЦвет;
// Штатная палитра - 56 цветов
Область = Таб.Область(Стр, Кол+9);
Область.ЦветФона(РасшЦвет); // Происходит приведение расширенного цвета к штатному
Область.Текст = Область.ЦветФона(); // Получаем уже приведенный цвет
КонецЦикла;
КонецЦикла;
Таб.Показать();
КонецПроцедуры
Этот подход позволяет визуализировать расширенный спектр цветов непосредственно в ячейках отчета. К сожалению, сам объект Диаграмма.ЦветСерии не управляется через tabledoc.dll напрямую, поэтому для диаграмм нам по-прежнему приходится ориентироваться на приведенные (штатные) цвета.
Если стандартный графический движок 1С 7.7 вас категорически не устраивает по качеству рендеринга, отсутствию сглаживания или невозможности повернуть подписи по осям вертикально, рекомендуем рассмотреть альтернативные варианты решения задачи.
Это специализированная бесплатная компонента, предназначенная для вывода графиков непосредственно на формы или в таблицы 1С 7.7. Она полностью решает проблему искажения цветов:
С помощью мощной внешней компоненты 1С++ на форму отчета 1С 7.7 можно внедрить стандартный контейнер ActiveX и загрузить туда библиотеку деловой графики Microsoft (например, OWC10.ChartSpace или OWC11.ChartSpace, поставляемые вместе с MS Office).
Этот метод предоставляет разработчику практически безграничные возможности:
Вместо формирования штатной диаграммы мы можем внедрить OLE-объект листа Excel непосредственно в табличный документ .mxl. При формировании отчета код 1С через COM-соединение обращается к структуре этого OLE-объекта, передает туда массив данных из Таблицы Значений и командует Excel построить график.
Преимущества метода: на выходе мы получаем безупречно выглядящую диаграмму Excel, которую легко распечатать или сохранить вместе с отчетом в формате XLS.
Недостатки: данный метод требует обязательного наличия установленного MS Excel на рабочем месте каждого пользователя, а скорость формирования такого графического отчета будет существенно ниже по сравнению со штатными алгоритмами.