Добавляем жизни в таблицы и матрицы Power BI. Часть 2 — индикаторы в виде шкал

Привет!

В прошлом посте я показывал каким образом можно добавлять динамические индикаторы в матрицы и таблицы.
Теперь давайте подробно разберем как это работает и как можно достаточно быстро создавать свои динамические индикаторы. Если кратко, то мера возвращает код svg-изображения, а категория данных «URL-адрес изображения» указывает Power BI на то, что данную меру нужно отрисовать как картинку. Начнем по порядку.
SVG — стандарт векторных изображений, которые определяются не особо сложным для чтения человеком кодом и без особых проблем отрисовываются всеми современными браузерами. Сегодня не буду вдаваться в спецификацию стандарта svg, а просто разберу пошагово процесс создания индикатора:

Шаг 1. Создаем svg-контейнер:

<svg xmlns=’http://www.w3.org/2000/svg’ x= ‘0px’ y = ‘0px’ width=’100′ height=’100′></svg>
Здесь есть два важных момента:
1. Если Вы создаете svg-изображение в каком-либо редакторе, то все значения параметров заключаются в двойные кавычки. Для того, чтобы код заработал в Power BI кавычки должны быть одинарными.
2. Для того, чтобы Power BI корректно отрисовал SVG-изображение, перед объявлением svg-контейнера нужно добавить следующий текст (включая запятую на конце): data:image/svg+xml;utf8,

Шаг 2. Добавляем окружность:

Далее внутри svg-контейнера добавляем окружность для основного цвета шкалы:
<circle r=’40’ cx=’50’ cy=’50’ stroke=’green’ stroke-width=’10’ fill=’none’></circle>
r — радиус окружности
cx,cy — координаты центра окружности
stroke и stroke-width — цвет и толщина внешнего контура
fill — цвет заливки круга.

Не забываем «обернуть» код svg-изображения в кавычки при написании меры. Если всё сделали правильно, то на этом этапе мера будет возвращать зеленую окружность:
Circle_Measure =
«data:image/svg+xml;utf8,»
«<svg xmlns=’http://www.w3.org/2000/svg’ x= ‘0px’ y = ‘0px’ width=’100′ height=’100′>»
«<circle r=’40’ cx=’50’ cy=’50’ stroke=’green’ stroke-width=’10’ fill=’none’></circle>»
«</svg>»

 

 

 

 

Шаг 3. Получаем полуокружность:

Для того, чтобы превратить окружность в полукруг, используем параметр stroke-dasharray, который превращает сплошную кривую в штриховую и принимает на вход два значения: длина штриха и длина пробела. Поскольку требуется получить полукруг, то длина штриха должна быть равна половине длины окружности, а длина промежутка быть больше, так что зададим ее равной длине окружности. Напомним, что длина окружности L рассчитывается по формуле L = 2*Pi*R, где R это радиус окружности. В нашем примере: stroke-dasharray = «125.6 ,251.2» и мера принимает вид:

Half_Circle_Measure =
«data:image/svg+xml;utf8,»
«<svg xmlns=’http://www.w3.org/2000/svg’ x= ‘0px’ y = ‘0px’ width=’100′ height=’100′>»
«<circle r=’40’ cx=’50’ cy=’50’ stroke=’green’ stroke-width=’10’  fill=’none’ «
«stroke-dasharray = ‘125.6 ,251.2’></circle>»
«</svg>»

 

 

 

 

 

Шаг 4. Поворачиваем полуокружность:

Созданная нами мера отрисовывает нижнюю половину окружности, поэтому нам нужно ее повернуть, чтобы достичь желаемого результата. Обратите внимание, что отрисовка линии начинается с крайней правой точки  (X = cx+r, Y = cy)  окружности по часовой стрелки. Для выполнения поворота используется параметр «tranform»:  transform= «rotate(Угол поворота,X,Y)», где X,Y — координаты точки, вокруг которой будет осуществлен поворот. В нашем случае они совпадают с координатами центра окружности: transform= «rotate(180,50,50)» и мера принимает вид:

Green_Scale =
«data:image/svg+xml;utf8,»
«<svg xmlns=’http://www.w3.org/2000/svg’ x= ‘0px’ y = ‘0px’ width=’100′ height=’100′>»
«<circle r=’40’ cx=’50’ cy=’50’ stroke=’green’ stroke-width=’10’  fill=’none’ «
«stroke-dasharray = ‘125.6 ,251.2’ transform= ‘rotate(180,50,50)’></circle>»
«</svg>»

 

 

 

Шаг 5. Добавляем красный и желтый участки шкалы:

Теперь нужно добавить красную часть шкалы. Для этого также будет использоваться окружность. Представим, что красная зона должна занимать 0,4 всей шкалы. Параметр stroke-dasharray принимает вид: «stroke-dasharray = ‘125.6 x 0,4 ,251.2’.  Для того, чтобы красная дуга находилась в верхней части окружности задаем такое же значение параметра transform, как и для зеленой полуокружности.

Red_Scale =
«data:image/svg+xml;utf8,»
«<svg xmlns=’http://www.w3.org/2000/svg’ x= ‘0px’ y = ‘0px’ width=’100′ height=’100′>»
«<circle r=’40’ cx=’50’ cy=’50’ stroke=’red’ stroke-width=’10’  fill=’none’ «
«stroke-dasharray = ‘50.24 ,251.2’ transform= ‘rotate(180,50,50)’></circle>»
«</svg>»

Желтая часть рассчитывается также как и красная. Пусть она должна занимать 0,3 шкалы. В этом случае длина дуги должна быть 0,7 длины полуокружности = 0,4 длина красной зоны + 0,3 длина желтой зоны.

Yellow_Scale =
«data:image/svg+xml;utf8,»
«<svg xmlns=’http://www.w3.org/2000/svg’ x= ‘0px’ y = ‘0px’ width=’100′ height=’100′>»
«<circle r=’40’ cx=’50’ cy=’50’ stroke=’yellow’ stroke-width=’10’  fill=’none’ «
«stroke-dasharray = ‘87.92 ,251.2’ transform= ‘rotate(180,50,50)’></circle>»
«</svg>»

 

 

 

Шаг 6. Объединяем шкалы и добавляем указатель:

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

Gauge_scale =
«data:image/svg+xml;utf8,»
«<svg xmlns=’http://www.w3.org/2000/svg’ x= ‘0px’ y = ‘0px’ width=’100′ height=’100′>»
«<circle r=’40’ cx=’50’ cy=’50’ stroke=’green’ stroke-width=’10’  fill=’none’ « //Зеленая дуга
«stroke-dasharray = ‘125.6 ,251.2’ transform= ‘rotate(180,50,50)’></circle>»
«<circle r=’40’ cx=’50’ cy=’50’ stroke=’yellow’ stroke-width=’10’  fill=’none’ «
«stroke-dasharray = ‘87.92 ,251.2’ transform= ‘rotate(180,50,50)’></circle>» //Жёлтая дуга
«<circle r=’40’ cx=’50’ cy=’50’ stroke=’red’ stroke-width=’10’  fill=’none’ «
«stroke-dasharray = ‘50.24 ,251.2’ transform= ‘rotate(180,50,50)’></circle>» //Красная дуга
«</svg>»

 

 

 

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

Line =
«data:image/svg+xml;utf8,»
«<svg xmlns=’http://www.w3.org/2000/svg’ x= ‘0px’ y = ‘0px’ width=’100′ height=’100′>»
«<line x1=’50’ y1=’50’ x2=’10’ y2=’50’ stroke=’black’ stroke-width=’2′ transform=’rotate(60,50,50)’ />»
«</svg>»

X1, y1 ,x2, y2 — координаты начала и конца линии, соответственно. Поскольку требуется, чтобы длина линии равная радиусу внутренней дуги шкалы, то координату x2 задаем равной толщине дуги.

 

 

 

 

Итоговый вид меры:

Static_gauge =
«data:image/svg+xml;utf8,»
«<svg xmlns=’http://www.w3.org/2000/svg’ x= ‘0px’ y = ‘0px’ width=’100′ height=’100′>»
«<circle r=’40’ cx=’50’ cy=’50’ stroke=’green’ stroke-width=’10’  fill=’none’ « //Зеленая дуга
«stroke-dasharray = ‘125.6 ,251.2’ transform= ‘rotate(180,50,50)’></circle>»
«<circle r=’40’ cx=’50’ cy=’50’ stroke=’yellow’ stroke-width=’10’  fill=’none’ «
«stroke-dasharray = ‘87.92 ,251.2’ transform= ‘rotate(180,50,50)’></circle>» //Жёлтая дуга
«<circle r=’40’ cx=’50’ cy=’50’ stroke=’red’ stroke-width=’10’  fill=’none’ «
«stroke-dasharray = ‘50.24 ,251.2’ transform= ‘rotate(180,50,50)’></circle>» //Красная дуга
«<line x1=’50’ y1=’50’ x2=’10’ y2=’50’ stroke=’black’ stroke-width=’2′ transform=’rotate(120,50,50)’ />» //Указатель
«</svg>»

Заключительный шаг:

Теперь все, или почти все числовые значения можно определить в виде параметров. Обратите особое внимание, что в результате расчетов практически все параметры могут быть дробными с большим количеством десятичных знаков. Это может привести к тому, что изображение будет некорректно сформировано (задайте угол поворота, например, 76.12433648353), поэтому рекомендую использовать DAX функцию ROUND и округлять получившиеся значения параметров до целого числа или до 1-2 десятичных знаков.

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

Пример можно скачать здесь.

 

Добавить комментарий

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

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.