Skip to content
This repository was archived by the owner on May 5, 2021. It is now read-only.

Commit 89f876b

Browse files
authored
Merge pull request SORMAS-Foundation#2808 from hzi-braunschweig/feature-2753-CampaignDiagram
Feature 2753 campaign diagram
2 parents 267c853 + 4e60ac8 commit 89f876b

10 files changed

Lines changed: 145 additions & 89 deletions

File tree

sormas-api/src/main/java/de/symeda/sormas/api/campaign/diagram/CampaignDiagramDataDto.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,18 @@ public class CampaignDiagramDataDto implements Serializable {
1414
private Object groupingKey;
1515
private String groupingCaption;
1616

17-
public CampaignDiagramDataDto(String formMetaUuid, String formId, String fieldId, Object valueSum, Object groupingKey, String groupingCaption) {
17+
public CampaignDiagramDataDto(
18+
String formMetaUuid,
19+
String formId,
20+
String fieldId,
21+
String fieldCaption,
22+
Object valueSum,
23+
Object groupingKey,
24+
String groupingCaption) {
1825
this.formMetaUuid = formMetaUuid;
1926
this.formId = formId;
2027
this.fieldId = fieldId;
28+
this.fieldCaption = fieldCaption;
2129
this.valueSum = valueSum;
2230
this.groupingKey = groupingKey;
2331
this.groupingCaption = groupingCaption;

sormas-api/src/main/java/de/symeda/sormas/api/campaign/form/CampaignFormElement.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
public class CampaignFormElement implements Serializable {
66

7+
public static final String ID = "id";
8+
public static final String TYPE = "type";
9+
public static final String CAPTION = "caption";
10+
711
private static final long serialVersionUID = 5553496750859734167L;
812

913
public static final String[] VALID_TYPES = {

sormas-api/src/main/java/de/symeda/sormas/api/region/RegionFacade.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
@Remote
3030
public interface RegionFacade {
3131

32+
List<RegionReferenceDto> getAllActiveByArea(String areaUuid);
33+
3234
List<RegionReferenceDto> getAllActiveAsReference();
3335

3436
List<RegionDto> getAllAfter(Date date);

sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/data/CampaignFormDataFacadeEjb.java

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import java.sql.Timestamp;
2424
import java.util.ArrayList;
2525
import java.util.List;
26-
import java.util.Optional;
2726
import java.util.stream.Collectors;
2827

2928
import javax.ejb.EJB;
@@ -53,7 +52,8 @@
5352
import de.symeda.sormas.api.campaign.diagram.CampaignDiagramDataDto;
5453
import de.symeda.sormas.api.campaign.diagram.CampaignDiagramSeries;
5554
import de.symeda.sormas.api.campaign.form.CampaignFormElement;
56-
import de.symeda.sormas.api.campaign.form.CampaignFormMetaDto;
55+
import de.symeda.sormas.api.campaign.form.CampaignFormElementType;
56+
import de.symeda.sormas.api.region.AreaReferenceDto;
5757
import de.symeda.sormas.api.region.DistrictReferenceDto;
5858
import de.symeda.sormas.api.region.RegionReferenceDto;
5959
import de.symeda.sormas.api.user.UserRight;
@@ -66,6 +66,7 @@
6666
import de.symeda.sormas.backend.campaign.form.CampaignFormMetaFacadeEjb;
6767
import de.symeda.sormas.backend.campaign.form.CampaignFormMetaService;
6868
import de.symeda.sormas.backend.common.AbstractDomainObject;
69+
import de.symeda.sormas.backend.region.Area;
6970
import de.symeda.sormas.backend.region.Community;
7071
import de.symeda.sormas.backend.region.CommunityFacadeEjb;
7172
import de.symeda.sormas.backend.region.CommunityService;
@@ -293,41 +294,56 @@ public List<CampaignDiagramDataDto> getDiagramData(
293294

294295
for (CampaignDiagramSeries diagramSeries : diagramSeriesList) {
295296

296-
// TODO check data type of field
297-
// - int: as-is
298-
// - yes-no/other: CampaignDiagramSeries.fieldValue should be defined -> count the number of form data that match the value
299-
300297
//@formatter:off
298+
final AreaReferenceDto area = campaignDiagramCriteria.getArea();
301299
final RegionReferenceDto region = campaignDiagramCriteria.getRegion();
302300
final DistrictReferenceDto district = campaignDiagramCriteria.getDistrict();
303301
final CampaignReferenceDto campaign = campaignDiagramCriteria.getCampaign();
302+
303+
final String areaFilter = area != null ? " AND " + Area.TABLE_NAME + "." + Area.UUID + " = '" + area.getUuid() + "'": "";
304304
final String regionFilter = region != null ? " AND " + CampaignFormData.REGION + "." + Region.UUID + " = '" + region.getUuid() + "'": "";
305305
final String districtFilter = district != null ? " AND " + CampaignFormData.DISTRICT + "." + District.UUID + " = '" + district.getUuid() + "'" : "";
306306
final String campaignFilter = campaign != null ? " AND " + Campaign.TABLE_NAME + "." + Campaign.UUID + " = '" + campaign.getUuid() + "'" : "";
307307
final String jurisdictionGrouping =
308-
district != null ? ", " + Community.TABLE_NAME + "." + Community.UUID + ", " + Community.TABLE_NAME + "." + Community.NAME :
309-
region != null ? ", " + District.TABLE_NAME + "." + District.UUID + ", " + District.TABLE_NAME + "." + District.NAME : "";
308+
(district != null ? ", " + Community.TABLE_NAME + "." + Community.UUID + ", " + Community.TABLE_NAME + "." + Community.NAME :
309+
region != null ? ", " + District.TABLE_NAME + "." + District.UUID + ", " + District.TABLE_NAME + "." + District.NAME : "")
310+
+ ", " + Region.TABLE_NAME + "." + Region.UUID + ", " + Region.TABLE_NAME + "." + Region.NAME;
311+
310312
Query seriesDataQuery = em.createNativeQuery(
311-
"SELECT " + CampaignFormMeta.TABLE_NAME + "." + CampaignFormMeta.UUID + " as campaignFormUuid," + CampaignFormMeta.TABLE_NAME + "." + CampaignFormMeta.FORM_ID
312-
+ ", jsonData->>'" + CampaignFormDataEntry.ID + "'"
313-
+ ", sum((jsonData->>'" + CampaignFormDataEntry.VALUE + "')\\:\\:int)"
314-
+ ", " + Region.TABLE_NAME + "." + Region.UUID + ", " + Region.TABLE_NAME + "." + Region.NAME
313+
"SELECT " + CampaignFormMeta.TABLE_NAME + "." + CampaignFormMeta.UUID + " as formUuid,"
314+
+ CampaignFormMeta.TABLE_NAME + "." + CampaignFormMeta.FORM_ID + " as formId"
315+
+ ", jsonData->>'" + CampaignFormDataEntry.ID + "' as fieldId"
316+
+ ", jsonMeta->>'" + CampaignFormElement.CAPTION + "' as fieldCaption"
317+
+ ", CASE"
318+
+ " WHEN (jsonMeta ->> '" + CampaignFormElement.TYPE + "') = '" + CampaignFormElementType.NUMBER.toString() + "' THEN sum((jsonData->>'" + CampaignFormDataEntry.VALUE + "')\\:\\:int)"
319+
+ " ELSE count((jsonData->>'" + CampaignFormDataEntry.VALUE + "') = '" + diagramSeries.getFieldValue() + "')"
320+
+ " END as sumValue"
321+
+ ", " + Region.TABLE_NAME + "." + Region.UUID
322+
+ ", " + Region.TABLE_NAME + "." + Region.NAME
315323
+ " FROM " + CampaignFormData.TABLE_NAME
316324
+ " LEFT JOIN " + CampaignFormMeta.TABLE_NAME + " ON " + CampaignFormData.CAMPAIGN_FORM_META + "_id = " + CampaignFormMeta.TABLE_NAME + "." + CampaignFormMeta.ID
317325
+ " LEFT JOIN " + Region.TABLE_NAME + " ON " + CampaignFormData.REGION + "_id = " + Region.TABLE_NAME + "." + Region.ID
326+
+ " LEFT JOIN " + Area.TABLE_NAME + " ON " + Region.AREA + "_id = " + Area.TABLE_NAME + "." + Area.ID
318327
+ " LEFT JOIN " + District.TABLE_NAME + " ON " + CampaignFormData.DISTRICT + "_id = " + District.TABLE_NAME + "." + District.ID
328+
+ " LEFT JOIN " + Community.TABLE_NAME + " ON " + CampaignFormData.COMMUNITY + "_id = " + Community.TABLE_NAME + "." + Community.ID
319329
+ " LEFT JOIN " + Campaign.TABLE_NAME + " ON " + CampaignFormData.CAMPAIGN + "_id = " + Campaign.TABLE_NAME + "." + Campaign.ID
320-
+ ", json_array_elements(" + CampaignFormData.FORM_VALUES + ") jsonData"
321-
+ " WHERE " + CampaignFormMeta.TABLE_NAME + "." + CampaignFormMeta.FORM_ID + " = '" + diagramSeries.getFormId() + "'"
330+
+ ", json_array_elements(" + CampaignFormData.FORM_VALUES + ") as jsonData"
331+
+ ", json_array_elements(" + CampaignFormMeta.CAMPAIGN_FORM_ELEMENTS + ") as jsonMeta"
332+
+ " WHERE " + CampaignFormMeta.TABLE_NAME + "." + CampaignFormMeta.FORM_ID + " = '" + diagramSeries.getFormId() + "'"
322333
+ " AND jsonData->>'" + CampaignFormDataEntry.ID + "' = '" + diagramSeries.getFieldId() + "'"
323334
+ " AND jsonData->>'" + CampaignFormDataEntry.VALUE + "' IS NOT NULL"
335+
+ " AND jsonData->>'" + CampaignFormDataEntry.ID + "' = jsonMeta->>'" + CampaignFormElement.ID + "'"
336+
+ areaFilter
324337
+ regionFilter
325338
+ districtFilter
326-
+ campaignFilter
327-
+ " GROUP BY " + CampaignFormMeta.TABLE_NAME + "." + CampaignFormMeta.UUID + "," + CampaignFormMeta.TABLE_NAME + "." + CampaignFormMeta.FORM_ID
339+
+ campaignFilter
340+
+ " GROUP BY "
341+
+ CampaignFormMeta.TABLE_NAME + "." + CampaignFormMeta.UUID + ","
342+
+ CampaignFormMeta.TABLE_NAME + "." + CampaignFormMeta.FORM_ID
328343
+ ", jsonData->>'" + CampaignFormDataEntry.ID + "'"
329-
+ jurisdictionGrouping
330-
+ ", " + Region.TABLE_NAME + "." + Region.UUID + ", " + Region.TABLE_NAME + "." + Region.NAME);
344+
+ ", jsonMeta->>'" + CampaignFormElement.CAPTION + "'"
345+
+ ", jsonMeta->>'" + CampaignFormElement.TYPE + "'"
346+
+ jurisdictionGrouping);
331347
//@formatter:on
332348

333349
@SuppressWarnings("unchecked")
@@ -340,25 +356,12 @@ public List<CampaignDiagramDataDto> getDiagramData(
340356
(String) result[0],
341357
(String) result[1],
342358
(String) result[2],
343-
(Object) result[3],
344-
(String) result[4],
345-
(String) result[5]))
359+
(String) result[3],
360+
(Object) result[4],
361+
(String) result[5],
362+
(String) result[6]))
346363
.collect(Collectors.toList()));
347364
}
348-
349-
// TODO: 21/08/2020 extract caption directly from json with query
350-
resultData.forEach(campaignDiagramDataDto -> {
351-
final CampaignFormMetaDto formMeta = campaignFormMetaFacade.getCampaignFormMetaByUuid(campaignDiagramDataDto.getFormMetaUuid());
352-
final String fieldId = campaignDiagramDataDto.getFieldId();
353-
final Optional<CampaignFormElement> optionalCampaignFormElement =
354-
formMeta.getCampaignFormElements().stream().filter(campaignFormElement -> campaignFormElement.getId().equals(fieldId)).findFirst();
355-
if (optionalCampaignFormElement.isPresent()) {
356-
357-
campaignDiagramDataDto.setFieldCaption(optionalCampaignFormElement.get().getCaption());
358-
} else {
359-
campaignDiagramDataDto.setFieldCaption(fieldId);
360-
}
361-
});
362365
return resultData;
363366
}
364367

sormas-backend/src/main/java/de/symeda/sormas/backend/region/RegionFacadeEjb.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import de.symeda.sormas.api.region.RegionReferenceDto;
4949
import de.symeda.sormas.api.utils.SortProperty;
5050
import de.symeda.sormas.api.utils.ValidationRuntimeException;
51+
import de.symeda.sormas.backend.common.InfrastructureAdo;
5152
import de.symeda.sormas.backend.facility.Facility;
5253
import de.symeda.sormas.backend.infrastructure.PointOfEntry;
5354
import de.symeda.sormas.backend.infrastructure.PopulationDataFacadeEjb.PopulationDataFacadeEjbLocal;
@@ -74,6 +75,17 @@ public class RegionFacadeEjb implements RegionFacade {
7475
@EJB
7576
private AreaService areaService;
7677

78+
@Override
79+
public List<RegionReferenceDto> getAllActiveByArea(String areaUuid) {
80+
CriteriaBuilder cb = em.getCriteriaBuilder();
81+
CriteriaQuery<Region> cq = cb.createQuery(Region.class);
82+
Root<Region> root = cq.from(Region.class);
83+
cq.where(cb.and(cb.isFalse(root.get(InfrastructureAdo.ARCHIVED)), cb.equal(root.get(Region.AREA).get(Area.UUID), areaUuid)));
84+
cq.orderBy(cb.asc(root.get(Region.NAME)));
85+
86+
return em.createQuery(cq).getResultList().stream().map(f -> toReferenceDto(f)).collect(Collectors.toList());
87+
}
88+
7789
@Override
7890
public List<RegionReferenceDto> getAllActiveAsReference() {
7991
return regionService.getAllActive(Region.NAME, true).stream().map(f -> toReferenceDto(f)).collect(Collectors.toList());

sormas-backend/src/main/resources/sql/sormas_schema.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5254,4 +5254,13 @@ ALTER TABLE contact_history ADD COLUMN quarantineofficialordersentdate timestamp
52545254

52555255
INSERT INTO schema_version (version_number, comment) VALUES (249, 'Add "Official order sent" and corresponding date to cases and contacts #2847');
52565256

5257+
-- 2020-07-29 Campaign diagram visualisation refinement
5258+
5259+
ALTER TABLE campaignformmeta ALTER COLUMN campaignFormElements TYPE json USING campaignFormElements::json;
5260+
ALTER TABLE campaignformmeta ALTER COLUMN campaignFormTranslations TYPE json USING campaignFormTranslations::json;
5261+
ALTER TABLE campaignformmeta_history ADD COLUMN campaignFormElements json;
5262+
ALTER TABLE campaignformmeta_history ADD COLUMN campaignFormTranslations json;
5263+
5264+
INSERT INTO schema_version (version_number, comment) VALUES (250, 'Campaign diagram visualization refinement #2753');
5265+
52575266
-- *** Insert new sql commands BEFORE this line ***

sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/campaigndata/CampaignDataView.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
package de.symeda.sormas.ui.campaign.campaigndata;
1717

18-
import static com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
1918
import static de.symeda.sormas.ui.utils.FilteredGrid.EDIT_BTN_ID;
2019

2120
import java.util.List;
@@ -24,6 +23,7 @@
2423
import org.vaadin.hene.popupbutton.PopupButton;
2524

2625
import com.vaadin.icons.VaadinIcons;
26+
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
2727
import com.vaadin.server.StreamResource;
2828
import com.vaadin.ui.Alignment;
2929
import com.vaadin.ui.Button;
@@ -94,14 +94,7 @@ public CampaignDataView() {
9494

9595
filterForm.getField(CampaignFormDataCriteria.CAMPAIGN_FORM_META).addValueChangeListener(e -> {
9696
Object value = e.getProperty().getValue();
97-
if (value == null) {
98-
campaignFormElementImportance.setVisible(false);
99-
} else {
100-
campaignFormElementImportance.setVisible(true);
101-
if (campaignFormElementImportance.getValue() == null) {
102-
campaignFormElementImportance.setValue(CampaignFormElementImportance.ALL);
103-
}
104-
}
97+
campaignFormElementImportance.setVisible(value != null);
10598
});
10699

107100
campaignFormElementImportance.addValueChangeListener(e -> {
@@ -174,6 +167,7 @@ private void createImportanceFilterSwitch() {
174167
campaignFormElementImportance
175168
.setItemCaption(CampaignFormElementImportance.ALL, I18nProperties.getEnumCaption(CampaignFormElementImportance.ALL));
176169

170+
campaignFormElementImportance.setValue(CampaignFormElementImportance.IMPORTANT);
177171
campaignFormElementImportance.setVisible(false);
178172
}
179173

@@ -247,7 +241,11 @@ public void enter(ViewChangeEvent event) {
247241
params = params.substring(1);
248242
criteria.fromUrlParams(params);
249243
}
244+
245+
applyingCriteria = true;
250246
filterForm.setValue(criteria);
247+
applyingCriteria = false;
248+
251249
grid.reload();
252250

253251
super.enter(event);

sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/infrastructure/RegionEditForm.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,10 @@ protected void addFields() {
8181

8282
area.addItems(FacadeProvider.getAreaFacade().getAllActiveAsReference());
8383

84-
if (!create) {
85-
area.setEnabled(false);
86-
}
84+
// area can always be changed, as it's not directly use for data references of other entities (e.g. case)
85+
// if (!create) {
86+
// area.setEnabled(false);
87+
// }
8788
}
8889

8990
@Override

sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/campaigns/CampaignDashboardDiagramComponent.java

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
import java.util.Iterator;
77
import java.util.List;
88
import java.util.Map;
9+
import java.util.function.Function;
10+
import java.util.stream.Collectors;
911

10-
import com.vaadin.ui.Alignment;
1112
import com.vaadin.ui.HorizontalLayout;
12-
import com.vaadin.ui.Label;
1313
import com.vaadin.ui.VerticalLayout;
1414

1515
import de.symeda.sormas.api.campaign.diagram.CampaignDiagramDataDto;
@@ -39,14 +39,6 @@ public CampaignDashboardDiagramComponent(CampaignDiagramDefinitionDto diagramDef
3939
headerLayout.setSpacing(true);
4040
CssStyles.style(headerLayout, CssStyles.VSPACE_4);
4141

42-
Label headerLabel = new Label(diagramDefinition.getDiagramCaption());
43-
headerLabel.setSizeUndefined();
44-
CssStyles.style(headerLabel, CssStyles.H2, CssStyles.VSPACE_4, CssStyles.VSPACE_TOP_NONE);
45-
46-
headerLayout.addComponent(headerLabel);
47-
headerLayout.setComponentAlignment(headerLabel, Alignment.BOTTOM_LEFT);
48-
headerLayout.setExpandRatio(headerLabel, 1);
49-
5042
addComponent(headerLayout);
5143

5244
setWidth(100, Unit.PERCENTAGE);
@@ -62,56 +54,76 @@ public CampaignDashboardDiagramComponent(CampaignDiagramDefinitionDto diagramDef
6254
axisCaptions.put(diagramData.getGroupingKey(), diagramData.getGroupingCaption());
6355
}
6456

65-
// TODO key probably needs to be combination of form and field id
66-
String seriesKey = diagramData.getFieldId();
57+
String seriesKey = diagramData.getFormId() + diagramData.getFieldId();
6758
if (!diagramDataBySeriesAndXAxis.containsKey(seriesKey)) {
68-
diagramDataBySeriesAndXAxis.put(seriesKey, new HashMap<Object, CampaignDiagramDataDto>());
59+
diagramDataBySeriesAndXAxis.put(seriesKey, new HashMap<>());
60+
}
61+
Map<Object, CampaignDiagramDataDto> objectCampaignDiagramDataDtoMap = diagramDataBySeriesAndXAxis.get(seriesKey);
62+
if (objectCampaignDiagramDataDtoMap.containsKey(diagramData.getGroupingKey())) {
63+
throw new RuntimeException("Campaign diagram data map already contains grouping");
6964
}
70-
// TODO throw exception when entry already exists
71-
diagramDataBySeriesAndXAxis.get(seriesKey).put(diagramData.getGroupingKey(), diagramData);
65+
objectCampaignDiagramDataDtoMap.put(diagramData.getGroupingKey(), diagramData);
7266
}
7367

74-
buildDiagramChart();
68+
buildDiagramChart(diagramDefinition.getDiagramCaption());
7569
}
7670

77-
private void buildDiagramChart() {
71+
private void buildDiagramChart(String title) {
7872
final StringBuilder hcjs = new StringBuilder();
7973

8074
//@formatter:off
8175
hcjs.append("var options = {"
8276
+ "chart:{ "
8377
+ " type: 'column', "
84-
+ " backgroundColor: 'transparent' "
78+
+ " backgroundColor: 'transparent', "
79+
+ " borderRadius: '1', "
80+
+ " borderWidth: '1', "
81+
+ " spacing: [20, 20, 20, 20], "
8582
+ "},"
8683
+ "credits:{ enabled: false },"
8784
+ "exporting:{ "
8885
+ " enabled: true,"
8986
+ " buttons:{ contextButton:{ theme:{ fill: 'transparent' } } }"
9087
+ "},"
91-
+ "title:{ text: '' },");
88+
+ "legend: { backgroundColor: 'transparent', margin: 30 },"
89+
+ "colors: ['#FF0000','#6691C4','#ffba08','#519e8a','#ed254e','#39a0ed','#FF8C00','#344055','#D36135','#82d173'],"
90+
+ "title:{ text: '" + title + "'},");
9291
//@formatter:on
9392

94-
hcjs.append("xAxis: { categories: [");
93+
Map<String, Long> stackMap = diagramDefinition.getCampaignDiagramSeriesList()
94+
.stream()
95+
.filter(campaignDiagramSeries -> campaignDiagramSeries.getStack() != null)
96+
.map(campaignDiagramSeries -> campaignDiagramSeries.getStack())
97+
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
98+
99+
hcjs.append("xAxis: {");
100+
if (stackMap.size() > 1) {
101+
hcjs.append("opposite: true,");
102+
}
103+
hcjs.append("categories: [");
95104
for (Object axisKey : axisKeys) {
96105
hcjs.append("'").append(axisCaptions.get(axisKey)).append("',");
97106
}
98107
hcjs.append("]},");
99108

100109
//@formatter:off
101-
hcjs.append("yAxis: { min: 0, title: { text: ''}},");
110+
hcjs.append("yAxis: { min: 0, title: { text: ''}");
111+
if (stackMap.size() > 1) {
112+
hcjs.append(
113+
", stackLabels: {enabled: true,verticalAlign: 'bottom',crop: false,overflow: 'none',y: 20,formatter: function() { return this.stack;},style: { color: 'grey'}}");
114+
}
115+
hcjs.append("},");
102116
//@formatter:on
103117

104118
// series
105-
if (diagramDefinition.getCampaignDiagramSeriesList()
106-
.stream()
107-
.filter(campaignDiagramSeries -> campaignDiagramSeries.getStack() != null)
108-
.findAny()
109-
.isPresent()) {
110-
hcjs.append("plotOptions: {\n" + " column: {\n" + " stacking: 'normal'\n" + " }\n" + " },");
119+
120+
if (stackMap.size() > 0) {
121+
hcjs.append("plotOptions: {column: { stacking: 'normal'}},");
111122
}
123+
112124
hcjs.append("series: [");
113125
for (CampaignDiagramSeries series : diagramDefinition.getCampaignDiagramSeriesList()) {
114-
String seriesKey = series.getFieldId();
126+
String seriesKey = series.getFormId() + series.getFieldId();
115127
if (!diagramDataBySeriesAndXAxis.containsKey(seriesKey))
116128
continue;
117129

0 commit comments

Comments
 (0)