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

Добрый день.
Есть сущность “Задача”, в ней ассоциация OTM - сущность “Область”, в которой поля “подразделение”, “дата начала”, “дата окончания”. Нужно в экране редактирования задачи добавить диаграмму Ганта.
Настолько я смог разобраться - заданием DataSource создать диаграмму не получиться? Если пробую задать значения через ListDataProvier - то получаю NPE:


java.lang.NullPointerException
	at com.haulmont.charts.gui.amcharts.model.gson.DataItemsSerializer.serialize(DataItemsSerializer.java:66)
	at com.haulmont.charts.gui.amcharts.model.gson.DataProviderSerializer.serialize(DataProviderSerializer.java:20)
	at com.haulmont.charts.gui.amcharts.model.charts.AbstractChart.toString(AbstractChart.java:620)
	at com.haulmont.charts.web.toolkit.ui.amcharts.CubaAmchartsScene.beforeClientResponse(CubaAmchartsScene.java:358)
	at com.vaadin.server.communication.UidlWriter.write(UidlWriter.java:112)
...

Как правильно задавать значения диаграммы Ганта через DataProvider? Может где то можно посмотреть пример?

Здравствуйте, Алексей.

В нашем CUBA Sampler приложении Вы можете посмотреть пример создания диаграммы Ганта с использованием datasource. Также есть примеры использования ListDataProvider, но в сочетании с Pie chart.

Не могли бы Вы приложить маленький демонстрационный проект, чтобы я мог разобраться в причине возникновения NullPointerException.

С уважением,
Глеб

Спасибо за комментарий. Указанные материалы смотрел. В примере где используется DataProvider работа все равно идет с сущностями, а мне бы хотелось понять как работать с произвольными выбранными данными - через MapDataItem.

Сейчас я пытаюсь заполнить данные так:

private void fillGanttDiagramm() {
    ListDataProvider listDataProvider = new ListDataProvider();
    List<Area> areas = getItem().gArea();
    for (Area area : areas) {
        listDataProvider.addItem(createGanttDiagrammDataItem(area));
    }

    GanttChart chart = (GanttChart) ganttChart.getConfiguration();
    chart.setDataProvider(listDataProvider);
}

private DataItem createGanttDiagrammDataItem(Area area) {
    MapDataItem item = new MapDataItem();
    item.add("category", area.getDepartment().getName());
    item.add("dateBegin", area.getDateBegin());
    item.add("dateEnd", area.getDateEnd());
    return item;
}

Данные для диаграммы Ганта должны быть иерархические. т.е. есть основной итем, так называемая категория, который хранит коллекцию сегментов. Это хорошо видно на примере из CUBA Sampler, в котором сущность TaskSpan имеет коллекцию сущностей Segment. Если Вы хотите Описать подобное, используя MapDataItem, то одно из полей главного MapDataItem должно быть коллекцией вложенных MapDataItem.

Вот пример подобного описания:
chart-demo.xml


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        caption="msg://caption"
        class="com.company.demo.web.ui.chart.ChartDemo"
        messagesPack="com.company.demo.web.ui.chart"
        xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd">
    <dialogMode height="600"
                width="800"/>
    <layout>
        <chart:ganttChart id="ganttChart"
                          additionalSegmentFields="task"
                          balloonDateFormat="JJ:NN"
                          brightnessStep="7"
                          categoryField="category"
                          colorField="color"
                          columnWidth="0.5"
                          endDateField="end"
                          height="100%"
                          marginRight="70"
                          period="DAYS"
                          rotate="true"
                          segmentsField="segments"
                          startDate="2016-01-01"
                          startDateField="start"
                          theme="LIGHT"
                          width="100%">
            <chart:graph balloonText="&lt;strong&gt;[[task]]&lt;/strong&gt;: [[open]] - [[value]]"
                         fillAlphas="1"
                         lineAlpha="1"
                         lineColor="WHITE"/>
            <chart:valueAxis type="DATE"/>
            <chart:valueScrollbar autoGridCount="true"
                                  color="BLACK"/>
            <chart:chartCursor cursorAlpha="0"
                               cursorColor="#55bb76"
                               fullWidth="true"
                               valueLineAlpha="0.5"
                               valueBalloonsEnabled="false"
                               valueLineBalloonEnabled="true"
                               valueLineEnabled="true"
                               valueZoomable="true"
                               zoomable="false"/>
            <chart:export/>
        </chart:ganttChart>
    </layout>
</window>

ChartDemo.java


public class ChartDemo extends AbstractWindow {
    @Inject
    private Chart ganttChart;

    @Override
    public void init(Map<String, Object> params) {
        ListDataProvider dataProvider = new ListDataProvider();

        List<MapDataItem> segments = new ArrayList<>();
        segments.add(new MapDataItem(ParamsMap.of("start", "2016-01-01",
                "end", "2016-01-14", "task", "Gathering requirements", "color", "#b9783f")));
        segments.add(new MapDataItem(ParamsMap.of("start", "2016-01-16",
                "end", "2016-01-27", "task", "Producing specifications")));
        segments.add(new MapDataItem(ParamsMap.of("start", "2016-02-05",
                "end", "2016-04-18", "task", "Development")));
        segments.add(new MapDataItem(ParamsMap.of("start", "2016-04-18",
                "end", "2016-04-30", "task", "Testing and QA")));
        dataProvider.addItem(new MapDataItem(ParamsMap.of("category", "Module #1", "segments", segments)));

        segments = new ArrayList<>();
        segments.add(new MapDataItem(ParamsMap.of("start", "2016-01-01",
                "end", "2016-01-10", "task", "Gathering requirements", "color", "#cc4748")));
        segments.add(new MapDataItem(ParamsMap.of("start", "2016-01-12",
                "end", "2016-01-15", "task", "Producing specifications")));
        segments.add(new MapDataItem(ParamsMap.of("start", "2016-01-16",
                "end", "2016-02-05", "task", "Development")));
        segments.add(new MapDataItem(ParamsMap.of("start", "2016-02-10",
                "end", "2016-02-18", "task", "Testing and QA")));
        dataProvider.addItem(new MapDataItem(ParamsMap.of("category", "Module #2", "segments", segments)));

        ganttChart.getConfiguration().setDataProvider(dataProvider);
    }
}

Также Вы можете скачать этот пример с github.

С уважением,

Глеб

Спасибо за разъяснения.
Еще один небольшой вопрос - как изменить формат даты при наведении на объект (на скриншоте)? Пробовал balloonDateFormat=“DD.MM.YYYY” - не помогает.

Baloon

Из документации AmCharts следует, что balloonDateFormat работает только если не добавлен chartCursor, в противном случае нужно использовать атрибут categoryBalloonDateFormat у chartCursor, который работает только если categoryAxis парсит даты. Но к сожалению указанные выше настройки не применяются к диаграмам Ганта. В данном случае это проблема самих AmCharts и следует ждать когда они это пофиксят.

Я сделал по другому - указал в чарте dataDateFormat=“DD.MM.YYYY”, а при добавлении в MapDataItem дату указываю как строку по формату SimpleDateFormat dateFormat = new SimpleDateFormat(“dd.MM.yyyy”). Даты ставятся корректно в нужном формате.

Как можно переносить по словам названия категорий? А то у меня слишком длинные названия и занимают почти пол экрана.

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

С уважением,

Глеб

Уже не стоит - заменил пробелы и сработало. Спасибо.