Загрузка данных
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"autosize": {
"type": "none",
"contains": "padding"
},
"width": 1200,
"height": 700,
"padding": 0,
"signals": [
{
"name": "leftWidth",
"update": "width * 0.5"
},
{
"name": "rightWidth",
"update": "width - leftWidth"
},
{
"name": "headerHeight",
"update": "max(35, height * 0.06)"
},
{
"name": "bodyHeight",
"update": "height - headerHeight"
},
{
"name": "pairHeight",
"update": "max(48, height * 0.075)"
},
{
"name": "subRowHeight",
"update": "pairHeight / 2"
},
{
"name": "monthWidth",
"value": 90
},
{
"name": "bodyContentHeight",
"update": "length(data('rows')) * pairHeight"
}
],
"data": [
{
"name": "dataset"
},
{
"name": "monthly",
"source": "dataset",
"transform": [
{
"type": "aggregate",
"groupby": [
"Программа",
"Проект",
"Группа",
"Исполнитель",
"Месяц"
],
"fields": [
"План",
"Факт"
],
"ops": [
"max",
"max"
],
"as": [
"План",
"Факт"
]
},
{
"type": "formula",
"as": "rowKey",
"expr": "datum['Программа'] + '|' + datum['Проект'] + '|' + datum['Группа'] + '|' + datum['Исполнитель']"
}
]
},
{
"name": "rows",
"source": "monthly",
"transform": [
{
"type": "aggregate",
"groupby": [
"rowKey",
"Программа",
"Проект",
"Группа",
"Исполнитель"
]
},
{
"type": "collect",
"sort": {
"field": [
"Программа",
"Проект",
"Группа",
"Исполнитель"
],
"order": [
"ascending",
"ascending",
"ascending",
"ascending"
]
}
}
]
},
{
"name": "months",
"source": "monthly",
"transform": [
{
"type": "aggregate",
"groupby": [
"Месяц"
]
},
{
"type": "collect",
"sort": {
"field": "Месяц",
"order": "ascending"
}
}
]
},
{
"name": "cells",
"source": "monthly",
"transform": [
{
"type": "fold",
"fields": [
"План",
"Факт"
],
"as": [
"Строка",
"Часы"
]
}
]
}
],
"scales": [
{
"name": "xLeft",
"type": "band",
"domain": [
"Программа",
"Проект",
"Группа",
"Исполнитель",
"Строка"
],
"range": [
0,
{
"signal": "leftWidth"
}
],
"paddingInner": 0,
"paddingOuter": 0
},
{
"name": "yRows",
"type": "band",
"domain": {
"data": "rows",
"field": "rowKey"
},
"range": [
0,
{
"signal": "bodyContentHeight"
}
],
"paddingInner": 0,
"paddingOuter": 0
},
{
"name": "xMonths",
"type": "band",
"domain": {
"data": "months",
"field": "Месяц"
},
"range": [
0,
{
"signal": "length(data('months')) * monthWidth"
}
],
"paddingInner": 0,
"paddingOuter": 0
}
],
"marks": [
{
"name": "leftHeader",
"type": "group",
"encode": {
"enter": {
"x": {
"value": 0
},
"y": {
"value": 0
}
},
"update": {
"width": {
"signal": "leftWidth"
},
"height": {
"signal": "headerHeight"
}
}
},
"marks": [
{
"type": "rect",
"encode": {
"update": {
"x": {
"value": 0
},
"y": {
"value": 0
},
"width": {
"signal": "leftWidth"
},
"height": {
"signal": "headerHeight"
},
"fill": {
"value": "#F3F3F3"
}
}
}
},
{
"type": "text",
"from": {
"data": "xLeftHeaders"
},
"encode": {
"update": {
"x": {
"signal": "scale('xLeft', datum.column) + bandwidth('xLeft') / 2"
},
"y": {
"signal": "headerHeight / 2"
},
"text": {
"field": "column"
},
"align": {
"value": "center"
},
"baseline": {
"value": "middle"
},
"fontWeight": {
"value": "bold"
}
}
}
},
{
"type": "rule",
"from": {
"data": "xLeftHeaders"
},
"encode": {
"update": {
"x": {
"signal": "scale('xLeft', datum.column)"
},
"y": {
"value": 0
},
"y2": {
"signal": "headerHeight"
},
"stroke": {
"value": "#D9D9D9"
}
}
}
}
]
},
{
"name": "rightHeader",
"type": "group",
"clip": true,
"encode": {
"enter": {
"y": {
"value": 0
}
},
"update": {
"x": {
"signal": "leftWidth"
},
"width": {
"signal": "rightWidth"
},
"height": {
"signal": "headerHeight"
}
}
},
"marks": [
{
"type": "rect",
"encode": {
"update": {
"x": {
"value": 0
},
"y": {
"value": 0
},
"width": {
"signal": "rightWidth"
},
"height": {
"signal": "headerHeight"
},
"fill": {
"value": "#F3F3F3"
}
}
}
},
{
"type": "text",
"from": {
"data": "months"
},
"encode": {
"update": {
"x": {
"signal": "scale('xMonths', datum['Месяц']) + bandwidth('xMonths') / 2"
},
"y": {
"signal": "headerHeight / 2"
},
"text": {
"signal": "timeFormat(toDate(datum['Месяц']), '%m.%Y')"
},
"align": {
"value": "center"
},
"baseline": {
"value": "middle"
},
"fontWeight": {
"value": "bold"
}
}
}
},
{
"type": "rule",
"from": {
"data": "months"
},
"encode": {
"update": {
"x": {
"signal": "scale('xMonths', datum['Месяц'])"
},
"y": {
"value": 0
},
"y2": {
"signal": "headerHeight"
},
"stroke": {
"value": "#D9D9D9"
}
}
}
}
]
},
{
"name": "leftBody",
"type": "group",
"clip": true,
"encode": {
"enter": {
"x": {
"value": 0
}
},
"update": {
"y": {
"signal": "headerHeight"
},
"width": {
"signal": "leftWidth"
},
"height": {
"signal": "bodyHeight"
}
}
},
"marks": [
{
"type": "rule",
"from": {
"data": "rows"
},
"encode": {
"update": {
"x": {
"value": 0
},
"x2": {
"signal": "leftWidth"
},
"y": {
"signal": "scale('yRows', datum.rowKey)"
},
"stroke": {
"value": "#D9D9D9"
}
}
}
},
{
"type": "rule",
"from": {
"data": "rows"
},
"encode": {
"update": {
"x": {
"signal": "scale('xLeft', 'Строка')"
},
"x2": {
"signal": "leftWidth"
},
"y": {
"signal": "scale('yRows', datum.rowKey) + bandwidth('yRows') / 2"
},
"stroke": {
"value": "#A0A0A0"
},
"strokeDash": {
"value": [
4,
3
]
}
}
}
},
{
"type": "text",
"from": {
"data": "rows"
},
"encode": {
"update": {
"x": {
"signal": "scale('xLeft', 'Программа') + bandwidth('xLeft') / 2"
},
"y": {
"signal": "scale('yRows', datum.rowKey) + bandwidth('yRows') / 2"
},
"text": {
"field": "Программа"
},
"align": {
"value": "center"
},
"baseline": {
"value": "middle"
}
}
}
},
{
"type": "text",
"from": {
"data": "rows"
},
"encode": {
"update": {
"x": {
"signal": "scale('xLeft', 'Проект') + bandwidth('xLeft') / 2"
},
"y": {
"signal": "scale('yRows', datum.rowKey) + bandwidth('yRows') / 2"
},
"text": {
"field": "Проект"
},
"align": {
"value": "center"
},
"baseline": {
"value": "middle"
}
}
}
},
{
"type": "text",
"from": {
"data": "rows"
},
"encode": {
"update": {
"x": {
"signal": "scale('xLeft', 'Группа') + bandwidth('xLeft') / 2"
},
"y": {
"signal": "scale('yRows', datum.rowKey) + bandwidth('yRows') / 2"
},
"text": {
"field": "Группа"
},
"align": {
"value": "center"
},
"baseline": {
"value": "middle"
}
}
}
},
{
"type": "text",
"from": {
"data": "rows"
},
"encode": {
"update": {
"x": {
"signal": "scale('xLeft', 'Исполнитель') + bandwidth('xLeft') / 2"
},
"y": {
"signal": "scale('yRows', datum.rowKey) + bandwidth('yRows') / 2"
},
"text": {
"field": "Исполнитель"
},
"align": {
"value": "center"
},
"baseline": {
"value": "middle"
}
}
}
},
{
"type": "text",
"from": {
"data": "rows"
},
"encode": {
"update": {
"x": {
"signal": "scale('xLeft', 'Строка') + bandwidth('xLeft') / 2"
},
"y": {
"signal": "scale('yRows', datum.rowKey) + bandwidth('yRows') / 4"
},
"text": {
"value": "План"
},
"align": {
"value": "center"
},
"baseline": {
"value": "middle"
}
}
}
},
{
"type": "text",
"from": {
"data": "rows"
},
"encode": {
"update": {
"x": {
"signal": "scale('xLeft', 'Строка') + bandwidth('xLeft') / 2"
},
"y": {
"signal": "scale('yRows', datum.rowKey) + bandwidth('yRows') * 0.75"
},
"text": {
"value": "Факт"
},
"align": {
"value": "center"
},
"baseline": {
"value": "middle"
}
}
}
},
{
"type": "rule",
"from": {
"data": "xLeftHeaders"
},
"encode": {
"update": {
"x": {
"signal": "scale('xLeft', datum.column)"
},
"y": {
"value": 0
},
"y2": {
"signal": "bodyContentHeight"
},
"stroke": {
"value": "#D9D9D9"
}
}
}
}
]
},
{
"name": "rightBody",
"type": "group",
"clip": true,
"encode": {
"update": {
"x": {
"signal": "leftWidth"
},
"y": {
"signal": "headerHeight"
},
"width": {
"signal": "rightWidth"
},
"height": {
"signal": "bodyHeight"
}
}
},
"marks": [
{
"type": "rule",
"from": {
"data": "rows"
},
"encode": {
"update": {
"x": {
"value": 0
},
"x2": {
"signal": "length(data('months')) * monthWidth"
},
"y": {
"signal": "scale('yRows', datum.rowKey)"
},
"stroke": {
"value": "#D9D9D9"
}
}
}
},
{
"type": "rule",
"from": {
"data": "rows"
},
"encode": {
"update": {
"x": {
"value": 0
},
"x2": {
"signal": "length(data('months')) * monthWidth"
},
"y": {
"signal": "scale('yRows', datum.rowKey) + bandwidth('yRows') / 2"
},
"stroke": {
"value": "#A0A0A0"
},
"strokeDash": {
"value": [
4,
3
]
}
}
}
},
{
"type": "rule",
"from": {
"data": "months"
},
"encode": {
"update": {
"x": {
"signal": "scale('xMonths', datum['Месяц'])"
},
"y": {
"value": 0
},
"y2": {
"signal": "bodyContentHeight"
},
"stroke": {
"value": "#E0E0E0"
}
}
}
},
{
"type": "text",
"from": {
"data": "cells"
},
"encode": {
"update": {
"x": {
"signal": "scale('xMonths', datum['Месяц']) + bandwidth('xMonths') / 2"
},
"y": {
"signal": "scale('yRows', datum.rowKey) + (datum['Строка'] === 'План' ? bandwidth('yRows') / 4 : bandwidth('yRows') * 0.75)"
},
"text": {
"signal": "datum['Часы'] == null ? '' : format(datum['Часы'], '.1f')"
},
"align": {
"value": "center"
},
"baseline": {
"value": "middle"
}
}
}
}
]
}
]
}