Перейти к содержанию

Чарт. Основные настройки#

Для начала создадим отдельную форму ChartForm и добавим ее в меню. В каталоге source/forms сделаем два файла, заберем из предыдущей практики таблицу, для демонстрации заполнения данных.

В ChartForm.xmlвставим код “Создание ChartForm.xml”:

<Form writeRoles='super' title='Chart Demo'>
  <ToolBar>
    <Tool id="toolBarItemExit" caption="Закрыть" image="current-theme/images/leftNavBar/close.png" clicked='toolBarItemExit_clicked'/>
  </ToolBar>
  <Layout type='bootstrap'>
    <Group id='group1' editorWidth='6'>
    <Grid caption='Товары' id='Grid1' editorWidth='6' selectionMode='multiplerows' height='400px' groupable='true' showAggregates='true' showStatusBar='true' >
        <ColumnGroup name="group1" text='Товар'> 
          <Column text='Группа' datafield='MaterialGroup' width='25%' >
            <TextBox />
          </Column>
          <Column text='Наименование' datafield='Material' width='50%' >
            <TextBox />
          </Column>
        </ColumnGroup>
        <Column text='Цена' datafield='Price' width='25%' cellsformat='D2' >
          <NumberInput />
        </Column>
      </Grid>
    </Group>
  </Layout>
</Form>

После 1-го Group вставим код элемента управления Chart: (Элемент управления Chart)

1
2
3
4
5
6
7
<Group id='group2' editorWidth='6'>
      <Chart id="chart1" editorWidth="6" width="100%" title="Товары" height="500px" colorScheme="scheme03" description="Диаграмма товара">
        <SeriesGroup displayValueAxis="true" type="pie">
          <Series dataField="Price" displayText="Material"/>
        </SeriesGroup>
      </Chart>
    </Group>

В ChartForm.js вставим код “Создание ChartForm.js”

import { Form } from 'ecosoft-lexema8'; // импорт компонентов из библиотеки ecosoft-lexema8
import template from './ChartForm.xml'; // импорт макета документа
export default class ChartForm extends Form {
  constructor(...args) {
    super(...args);
    this.controls.Grid1.dataSource = ko.mapping.fromJS(this.dataGrid);
    this.controls.Grid1.addGrouping('MaterialGroup', 0);
  }
  // макет документа
  static get template() {
    return template;
  }

  toolBarItemExit_clicked() {
    this.close();
  }

  get dataGrid() {
    return [
      {Price: 60.88, Material: 'Яблоки', MaterialGroup: 'Фрукты'}, 
      {Price: 80, Material: 'Апельсины', MaterialGroup: 'Фрукты'}, 
      {Price: 170.22, Material: 'Сыр Белебеевский', MaterialGroup: 'Сыры'}
    ]
  } 
}

В units.json добавим ссылку на форму (в массив views в существующей группе).

(код “Добавление в units.json”)

1
2
3
4
5
{
        "caption": "Чарт",
        "key": "ChartForm",
        "form": "./forms/ChartForm"
      }

Сохраним изменения. Проверим результат:

Добавим в панель управления (ToolBar) кнопку «Вывести», при нажатии на которую в чарте визуализируются данные из таблицы.

Добавьте в ChartForm.xml описание кнопки «Вывести» в ToolBar:

(код “Добавление кнопки «Вывести»”)

<Tool caption="Вывести" id="toolBarItemChartShow" image="current-theme/images/leftNavBar/pieChart.png" clicked='toolBarItemChartShow_clicked' />

Чарт как и прочие элементы управления принимает JS объекты в Observable формате. Так как в таблице они и так уже в этом формате, то просто заполняем чарт данными из грида.

В ChartForm.js добавим реализацию toolBarItemChartShow_clicked'.

(код “Добавление события кнопки «Вывести»”)

1
2
3
toolBarItemChartShow_clicked() {
    this.controls.chart1.dataSource = this.controls.Grid1.dataSource;
  }

Сохраним изменения и проверим результат:

При нажатии на кнопку получим результат:

Группировка данных#

Теперь поменяем группу, пусть теперь это будет MaterialGroup

(код “Смена группировки диаграммы в ChartForm.xml на группировку по MaterialGroup”)

<Series dataField="Price" displayText="MaterialGroup"/>

Результат:

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

Добавим в класс формы новую функцию, которая будет возвращать сгруппированные данные.

(код “Группировка диаграммы по MaterialGroup в ChartForm.js с помощью функции getGroupedData()”)

1
2
3
4
5
6
7
getGroupedData() {
    let obj = {};
    this.controls.Grid1.dataSource().forEach(f => {
      obj[f.MaterialGroup()] = (obj[f.MaterialGroup()] || 0) + f.Price();
    })
    return Object.keys(obj).map(key => ({ Group: key, Value: obj[key] }));
  }

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

И заменим заполнение чарта свойством.

(код “Реализация кнопки «Вывести» с помощью функции getGroupedData()”)

this.controls.chart1.dataSource = ko.mapping.fromJS(this.getGroupedData());

В ChartForm.js поменяем параметры для Series.

(код “Смена группировки диаграммы в ChartForm.xml на настраиваемую пользователем группировку”)

<Series dataField="Value" displayText="Group"/>

Сохраним изменения и проверим результат:

Сделаем функцию getGroupedData() универсальной. Пусть принимает параметр, по которому надо группировать.

(код “Группировка диаграммы по параметру функции getGroupedData() в ChartForm.js”)

1
2
3
4
5
6
7
getGroupedData(param) {
    let obj = {};
    this.controls.Grid1.dataSource().forEach(f => {
      obj[f[param]()] = (obj[f[param]()] || 0) + f.Price();
    })
    return Object.keys(obj).map(key => ({ Group: key, Value: obj[key] }));
  }

Группировать будем по текущей группировке Grid, если её нет, то по 'MaterialGroup'.

(код “Реализация кнопки «Вывести» с настраиваемой пользователем группировкой”)

1
2
3
4
toolBarItemChartShow_clicked() {
    const grouping = this.controls.Grid1.getGrouping()[0] || 'MaterialGroup';
    this.controls.chart1.dataSource = ko.mapping.fromJS(this.getGroupedData(grouping));
  }

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

Нет группировки:

по Товару:

по Группе товаров:

Дополнительные параметры#

Добавим вывод значений каждого кусочка нашего пирога. Вынесем настройки в отдельную функцию и вызовем ее в конструкторе.

(код “Реализация функции setChartSettings() с выводом значений по группам”)

1
2
3
setChartSettings() {
    this.controls.chart1.instance.seriesGroups[0].series[0].showLabels = true;
  }

(код “Вызов функции setChartSettings() в конструкторе”)

1
2
3
4
5
6
7
constructor(...args) {
    super(...args);
    this.controls.Grid1.dataSource = ko.mapping.fromJS(this.dataGrid);
    this.controls.Grid1.addGrouping('MaterialGroup', 0);

    this.setChartSettings();
  }

Результат:

Изменим радиус круга:

(код “Реализация функции setChartSettings() с изменением радиуса диаграммы”)

this.controls.chart1.instance.seriesGroups[0].series[0].radius = 120;

Результат:

Изменим формат выведенного значения, добавив “руб.” в конце. (код “Реализация функции setChartSettings() с добавлением «руб.»”)

1
2
3
this.controls.chart1.instance.seriesGroups[0].series[0].formatFunction = function(value, {}, e) {
      return `${value} руб.`;
    };

Сохраним изменения и проверим результат:

Данная функция применяется для всех надписей на гриде, в том числе и на легенду. Поэтому чтобы “руб” добавлялся только для лейблов, функция:

(код “Реализация функции setChartSettings() с добавлением «руб.» для лейблов”)

1
2
3
this.controls.chart1.instance.seriesGroups[0].series[0].formatFunction = function(value, {}, e) {
      return (e || e.displayText == 'Group') ? `${value} руб.` : value;
    };

Выведем сумму внутри круга (код “Реализация функции setChartSettings() с лейблами внутри круга”)

1
2
3
4
this.controls.chart1.instance.seriesGroups[0].series[0].labels = {
      linesEnabled: false,
      radius: 100
    };

Сохраним изменения и проверим результат:

События#

Чарт поддерживает событие clicked. Подпишемся на это событие и в реализации сделаем вывод информации о выбранном кусочке пирога.

В ChartForm.xml добавьте в Chart свойство clicked (код “Добавление события для Chart в ChartForm.xml”)

clicked='chart1_clicked'

В ChartForm.js добавим реализацию (код “Реализация события при нажатии на сегмент Chart в ChartForm.js, вывод в консоли”)

1
2
3
4
chart1_clicked({}, { args }) {
    const { Group, Value } = this.controls.chart1.dataSource()[args.elementIndex];
    this.services.dialog.info(`${Group()} на сумму ${Value()} руб.`);
  }

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

(код “Реализация события при нажатии на сегмент Chart в ChartForm.js, вывод в «Инфо»”)

Из массива достаем свойства Group, Value и выводим их (вызвав как функцию, так как в dataSource объекты в Observable формате).

Результат при нажатии на группу “Фрукты”: