survey-analytics 2.3.10 → 2.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/fesm/shared.mjs +496 -32
  2. package/fesm/shared.mjs.map +1 -1
  3. package/fesm/shared2.mjs +696 -212
  4. package/fesm/shared2.mjs.map +1 -1
  5. package/fesm/survey.analytics.core.mjs +2 -2
  6. package/fesm/survey.analytics.mjs +26 -8
  7. package/fesm/survey.analytics.mjs.map +1 -1
  8. package/fesm/survey.analytics.mongo.mjs +1 -1
  9. package/fesm/survey.analytics.tabulator.mjs +33 -8
  10. package/fesm/survey.analytics.tabulator.mjs.map +1 -1
  11. package/package.json +4 -3
  12. package/survey-analytics-tabulator.types/analytics-localization/arabic.d.ts +16 -0
  13. package/survey-analytics-tabulator.types/analytics-localization/dutch.d.ts +16 -0
  14. package/survey-analytics-tabulator.types/analytics-localization/english.d.ts +16 -0
  15. package/survey-analytics-tabulator.types/analytics-localization/farsi.d.ts +16 -0
  16. package/survey-analytics-tabulator.types/analytics-localization/finnish.d.ts +16 -0
  17. package/survey-analytics-tabulator.types/analytics-localization/french.d.ts +16 -0
  18. package/survey-analytics-tabulator.types/analytics-localization/german.d.ts +16 -0
  19. package/survey-analytics-tabulator.types/analytics-localization/italian.d.ts +16 -0
  20. package/survey-analytics-tabulator.types/analytics-localization/japanese.d.ts +16 -0
  21. package/survey-analytics-tabulator.types/analytics-localization/norwegian.d.ts +16 -0
  22. package/survey-analytics-tabulator.types/analytics-localization/polish.d.ts +16 -0
  23. package/survey-analytics-tabulator.types/analytics-localization/portuguese.d.ts +16 -0
  24. package/survey-analytics-tabulator.types/analytics-localization/russian.d.ts +16 -0
  25. package/survey-analytics-tabulator.types/analytics-localization/spanish.d.ts +16 -0
  26. package/survey-analytics-tabulator.types/analytics-localization/swedish.d.ts +16 -0
  27. package/survey-analytics-tabulator.types/localizationManager.d.ts +16 -0
  28. package/survey-analytics-tabulator.types/tables/table.d.ts +19 -0
  29. package/survey-analytics-tabulator.types/tables/tabulator.d.ts +2 -0
  30. package/survey-analytics.types/analytics-localization/arabic.d.ts +16 -0
  31. package/survey-analytics.types/analytics-localization/dutch.d.ts +16 -0
  32. package/survey-analytics.types/analytics-localization/english.d.ts +16 -0
  33. package/survey-analytics.types/analytics-localization/farsi.d.ts +16 -0
  34. package/survey-analytics.types/analytics-localization/finnish.d.ts +16 -0
  35. package/survey-analytics.types/analytics-localization/french.d.ts +16 -0
  36. package/survey-analytics.types/analytics-localization/german.d.ts +16 -0
  37. package/survey-analytics.types/analytics-localization/italian.d.ts +16 -0
  38. package/survey-analytics.types/analytics-localization/japanese.d.ts +16 -0
  39. package/survey-analytics.types/analytics-localization/norwegian.d.ts +16 -0
  40. package/survey-analytics.types/analytics-localization/polish.d.ts +16 -0
  41. package/survey-analytics.types/analytics-localization/portuguese.d.ts +16 -0
  42. package/survey-analytics.types/analytics-localization/russian.d.ts +16 -0
  43. package/survey-analytics.types/analytics-localization/spanish.d.ts +16 -0
  44. package/survey-analytics.types/analytics-localization/swedish.d.ts +16 -0
  45. package/survey-analytics.types/dataProvider.d.ts +10 -0
  46. package/survey-analytics.types/entries/mongo.d.ts +1 -0
  47. package/survey-analytics.types/histogram.d.ts +48 -1
  48. package/survey-analytics.types/localizationManager.d.ts +16 -0
  49. package/survey-analytics.types/mongo/index.d.ts +16 -0
  50. package/survey-analytics.types/mongo/pipelines.d.ts +1 -0
  51. package/survey-analytics.types/mongo/result-transformers.d.ts +35 -0
  52. package/survey-analytics.types/selectBase.d.ts +3 -1
  53. package/survey-analytics.types/statisticCalculators.d.ts +12 -2
  54. package/survey-analytics.types/visualizationMatrixDropdown.d.ts +4 -6
  55. package/survey-analytics.types/visualizationPanel.d.ts +1 -0
  56. package/survey-analytics.types/visualizationPanelDynamic.d.ts +2 -5
  57. package/survey-analytics.types/visualizerBase.d.ts +2 -0
  58. package/survey.analytics.core.css +1 -1
  59. package/survey.analytics.core.d.ts +1 -0
  60. package/survey.analytics.core.js +1232 -218
  61. package/survey.analytics.core.js.map +1 -1
  62. package/survey.analytics.core.min.css +1 -1
  63. package/survey.analytics.core.min.js +1 -1
  64. package/survey.analytics.core.min.js.LICENSE.txt +1 -1
  65. package/survey.analytics.css +1 -1
  66. package/survey.analytics.d.ts +1 -0
  67. package/survey.analytics.js +1257 -223
  68. package/survey.analytics.js.map +1 -1
  69. package/survey.analytics.min.css +1 -1
  70. package/survey.analytics.min.js +1 -1
  71. package/survey.analytics.min.js.LICENSE.txt +1 -1
  72. package/survey.analytics.mongo.d.ts +1 -0
  73. package/survey.analytics.mongo.js +1 -1
  74. package/survey.analytics.mongo.min.js.LICENSE.txt +1 -1
  75. package/survey.analytics.tabulator.css +1 -1
  76. package/survey.analytics.tabulator.d.ts +1 -0
  77. package/survey.analytics.tabulator.js +529 -40
  78. package/survey.analytics.tabulator.js.map +1 -1
  79. package/survey.analytics.tabulator.min.css +1 -1
  80. package/survey.analytics.tabulator.min.js +1 -1
  81. package/survey.analytics.tabulator.min.js.LICENSE.txt +1 -1
package/fesm/shared2.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * surveyjs - SurveyJS Dashboard library v2.3.10
2
+ * surveyjs - SurveyJS Dashboard library v2.3.12
3
3
  * Copyright (c) 2015-2025 Devsoft Baltic OÜ - http://surveyjs.io/
4
4
  * License: MIT (http://www.opensource.org/licenses/mit-license.php)
5
5
  */
@@ -43,6 +43,10 @@ class DataProvider {
43
43
  constructor(_data = []) {
44
44
  this._data = _data;
45
45
  this.filterValues = {};
46
+ /**
47
+ * Fires when data has been changed.
48
+ */
49
+ this.onFilterChanged = new Event();
46
50
  /**
47
51
  * Fires when data has been changed.
48
52
  */
@@ -79,13 +83,17 @@ class DataProvider {
79
83
  const filterValueType = typeof filterValue;
80
84
  const questionValue = item[key];
81
85
  if (Array.isArray(questionValue)) {
82
- if (filterValueType !== "object")
86
+ if (filterValueType === "object") {
87
+ return !questionArrayValueContainsValue(questionValue, filterValue);
88
+ }
89
+ else {
83
90
  return questionValue.indexOf(filterValue) == -1;
91
+ }
84
92
  }
85
93
  if (typeof questionValue === "object") {
86
94
  if (filterValueType !== "object")
87
95
  return true;
88
- return !questionContainsValue(questionValue, filterValue);
96
+ return !questionValueContainsValue(questionValue, filterValue);
89
97
  }
90
98
  const seriesValue = item[DataProvider.seriesMarkerKey];
91
99
  if (!!seriesValue && filterValueType === "object") {
@@ -118,16 +126,37 @@ class DataProvider {
118
126
  var filterChanged = true;
119
127
  if (selectedValue !== undefined) {
120
128
  filterChanged = this.filterValues[questionName] !== selectedValue;
121
- this.filterValues[questionName] = selectedValue;
129
+ if (filterChanged) {
130
+ this.filterValues[questionName] = selectedValue;
131
+ }
122
132
  }
123
133
  else {
124
134
  filterChanged = this.filterValues[questionName] !== undefined;
125
- delete this.filterValues[questionName];
135
+ if (filterChanged) {
136
+ delete this.filterValues[questionName];
137
+ }
126
138
  }
127
139
  if (filterChanged) {
140
+ this.raiseFilterChanged(questionName, selectedValue);
128
141
  this.raiseDataChanged();
129
142
  }
130
143
  }
144
+ /**
145
+ * Resets filter.
146
+ */
147
+ resetFilter() {
148
+ if (Object.keys(this.filterValues).length === 0) {
149
+ return;
150
+ }
151
+ Object.keys(this.filterValues).forEach(key => delete this.filterValues[key]);
152
+ this.raiseFilterChanged();
153
+ this.raiseDataChanged();
154
+ }
155
+ raiseFilterChanged(questionName, selectedValue) {
156
+ if (!this.onFilterChanged.isEmpty) {
157
+ this.onFilterChanged.fire(this, { questionName, selectedValue });
158
+ }
159
+ }
131
160
  raiseDataChanged(questionName) {
132
161
  this._filteredData = undefined;
133
162
  if (!this.onDataChanged.isEmpty) {
@@ -137,9 +166,31 @@ class DataProvider {
137
166
  getFilters() {
138
167
  return Object.keys(this.filterValues).map(key => ({ field: key, type: "=", value: this.filterValues[key] }));
139
168
  }
169
+ fixDropdownData(dataNames) {
170
+ (this.data || []).forEach((dataItem) => {
171
+ let rawDataItem = dataItem[dataNames[0]];
172
+ if (!!rawDataItem && typeof rawDataItem === "object" && !Array.isArray(rawDataItem)) {
173
+ const arrayData = [];
174
+ Object.keys(rawDataItem).forEach((key) => {
175
+ var nestedDataItem = Object.assign({}, rawDataItem[key]);
176
+ nestedDataItem[DataProvider.seriesMarkerKey] = key;
177
+ arrayData.push(nestedDataItem);
178
+ });
179
+ dataItem[dataNames[0]] = arrayData;
180
+ }
181
+ });
182
+ }
140
183
  }
141
184
  DataProvider.seriesMarkerKey = "__sa_series_name";
142
- function questionContainsValue(questionValue, filterValue) {
185
+ function questionArrayValueContainsValue(questionValues, filterValue) {
186
+ for (let i = 0; i < questionValues.length; i++) {
187
+ if (questionValueContainsValue(questionValues[i], filterValue)) {
188
+ return true;
189
+ }
190
+ }
191
+ return false;
192
+ }
193
+ function questionValueContainsValue(questionValue, filterValue) {
143
194
  const questionValueKeys = Object.keys(questionValue);
144
195
  const filterValueKeys = Object.keys(filterValue);
145
196
  if (filterValueKeys.length > questionValueKeys.length)
@@ -335,51 +386,58 @@ function defaultStatisticsCalculator(data, dataInfo) {
335
386
  return valuesIndex[val.value];
336
387
  return valuesIndex[val];
337
388
  };
338
- data.forEach((row) => {
339
- dataNames.forEach((dataName, index) => {
340
- const rowValue = row[dataName];
341
- if (rowValue !== undefined || processMissingAnswers) {
342
- const rowValues = Array.isArray(rowValue) ? rowValue : [rowValue];
343
- if (series.length > 0) {
344
- const rowName = row[DataProvider.seriesMarkerKey];
345
- if (rowName !== undefined) {
346
- // Series are labelled by seriesMarkerKey in row data
347
- const seriesNo = seriesIndex[rowName] || 0;
348
- rowValues.forEach((val) => {
349
- const valIndex = getValueIndex(val);
350
- statistics[index][seriesNo][valIndex]++;
351
- });
352
- }
353
- else {
354
- // Series are the keys in question value (matrix question)
355
- // TODO: think about the de-normalization and combine with the previous case
356
- rowValues.forEach((val) => {
357
- series.forEach((seriesName) => {
358
- if (val[seriesName] !== undefined) {
359
- const seriesNo = seriesIndex[seriesName] || 0;
360
- const values = Array.isArray(val[seriesName]) ? val[seriesName] : [val[seriesName]];
361
- values.forEach(value => {
362
- const valIndex = getValueIndex(value);
363
- statistics[index][seriesNo][valIndex]++;
364
- });
365
- }
366
- });
367
- });
368
- }
389
+ const processDataRow = (dataRow, dataName, index) => {
390
+ const rowValue = dataRow[dataName];
391
+ if (rowValue !== undefined || processMissingAnswers) {
392
+ const rowValues = Array.isArray(rowValue) ? rowValue : [rowValue];
393
+ if (series.length > 0) {
394
+ const rowName = dataRow[DataProvider.seriesMarkerKey];
395
+ if (rowName !== undefined) {
396
+ // Series are labelled by seriesMarkerKey in row data
397
+ const seriesNo = seriesIndex[rowName] || 0;
398
+ rowValues.forEach((val) => {
399
+ const valIndex = getValueIndex(val);
400
+ statistics[index][seriesNo][valIndex]++;
401
+ });
369
402
  }
370
403
  else {
371
- // No series
404
+ // Series are the keys in question value (matrix question)
405
+ // TODO: think about the de-normalization and combine with the previous case
372
406
  rowValues.forEach((val) => {
373
- const valIndex = getValueIndex(val);
374
- statistics[0][0][valIndex]++;
407
+ series.forEach((seriesName) => {
408
+ if (val[seriesName] !== undefined) {
409
+ const seriesNo = seriesIndex[seriesName] || 0;
410
+ const values = Array.isArray(val[seriesName]) ? val[seriesName] : [val[seriesName]];
411
+ values.forEach(value => {
412
+ const valIndex = getValueIndex(value);
413
+ statistics[index][seriesNo][valIndex]++;
414
+ });
415
+ }
416
+ });
375
417
  });
376
418
  }
377
419
  }
420
+ else {
421
+ // No series
422
+ rowValues.forEach((val) => {
423
+ const valIndex = getValueIndex(val);
424
+ statistics[0][0][valIndex]++;
425
+ });
426
+ }
427
+ }
428
+ };
429
+ data.forEach((dataRow) => {
430
+ const nestedDataRows = getNestedDataRows(dataRow, dataInfo);
431
+ nestedDataRows.forEach(nestedDataRow => {
432
+ dataNames.forEach((dataName, index) => {
433
+ processDataRow(nestedDataRow, dataName, index);
434
+ });
378
435
  });
379
436
  });
380
437
  return dataInfo.dataNames.length > 1 ? statistics : statistics[0];
381
438
  }
382
- function histogramStatisticsCalculator(data, intervals, seriesValues) {
439
+ function histogramStatisticsCalculator(data, intervals, dataInfo, aggregateDataNames = []) {
440
+ const seriesValues = dataInfo.getSeriesValues();
383
441
  const statistics = [];
384
442
  if (seriesValues.length === 0) {
385
443
  seriesValues.push("");
@@ -388,8 +446,19 @@ function histogramStatisticsCalculator(data, intervals, seriesValues) {
388
446
  statistics.push(intervals.map(i => 0));
389
447
  data[seriesValues[i]].forEach(dataValue => {
390
448
  for (let j = 0; j < intervals.length; ++j) {
391
- if (intervals[j].start <= dataValue && (dataValue < intervals[j].end || j == intervals.length - 1)) {
392
- statistics[i][j]++;
449
+ if (intervals[j].start <= dataValue.continuous && (dataValue.continuous < intervals[j].end || j == intervals.length - 1)) {
450
+ if (aggregateDataNames.length > 0) {
451
+ aggregateDataNames.forEach(aggregateDataName => {
452
+ const aggregateDataValue = dataValue.row[aggregateDataName];
453
+ const numberValue = parseFloat(aggregateDataValue);
454
+ if (aggregateDataValue !== undefined && !isNaN(numberValue)) {
455
+ statistics[i][j] += numberValue;
456
+ }
457
+ });
458
+ }
459
+ else {
460
+ statistics[i][j]++;
461
+ }
393
462
  break;
394
463
  }
395
464
  }
@@ -397,21 +466,25 @@ function histogramStatisticsCalculator(data, intervals, seriesValues) {
397
466
  }
398
467
  return statistics;
399
468
  }
400
- function mathStatisticsCalculator(data, dataName) {
469
+ function mathStatisticsCalculator(data, dataInfo) {
401
470
  let resultMin = Number.MAX_VALUE, resultMax = -Number.MAX_VALUE, resultAverage = 0;
402
471
  let actualAnswerCount = 0;
403
- data.forEach((rowData) => {
404
- if (rowData[dataName] !== undefined) {
405
- const questionValue = +rowData[dataName];
406
- actualAnswerCount++;
407
- resultAverage += questionValue;
408
- if (resultMin > questionValue) {
409
- resultMin = questionValue;
410
- }
411
- if (resultMax < questionValue) {
412
- resultMax = questionValue;
472
+ data.forEach((dataRow) => {
473
+ const nestedDataRows = getNestedDataRows(dataRow, dataInfo);
474
+ nestedDataRows.forEach(nestedDataRow => {
475
+ const answerData = nestedDataRow[dataInfo.dataNames[0]];
476
+ if (answerData !== undefined) {
477
+ const questionValue = +answerData;
478
+ actualAnswerCount++;
479
+ resultAverage += questionValue;
480
+ if (resultMin > questionValue) {
481
+ resultMin = questionValue;
482
+ }
483
+ if (resultMax < questionValue) {
484
+ resultMax = questionValue;
485
+ }
413
486
  }
414
- }
487
+ });
415
488
  });
416
489
  if (actualAnswerCount > 0) {
417
490
  resultAverage = resultAverage / actualAnswerCount;
@@ -419,6 +492,25 @@ function mathStatisticsCalculator(data, dataName) {
419
492
  resultAverage = Math.ceil(resultAverage * 100) / 100;
420
493
  return [resultAverage, resultMin, resultMax];
421
494
  }
495
+ function getNestedDataRows(dataRow, dataInfo) {
496
+ let nestedDataRows = [];
497
+ if (!dataInfo.dataPath) {
498
+ nestedDataRows = [dataRow];
499
+ }
500
+ else {
501
+ if (dataRow[dataInfo.dataPath] === undefined)
502
+ return [];
503
+ if (typeof dataRow[dataInfo.dataPath] !== "object")
504
+ return [];
505
+ if (Array.isArray(dataRow[dataInfo.dataPath])) {
506
+ nestedDataRows = dataRow[dataInfo.dataPath];
507
+ }
508
+ else {
509
+ nestedDataRows = [dataRow[dataInfo.dataPath]];
510
+ }
511
+ }
512
+ return nestedDataRows;
513
+ }
422
514
 
423
515
  class PostponeHelper {
424
516
  static postpone(fn, timeout) {
@@ -573,6 +665,9 @@ class VisualizerBase {
573
665
  get dataNames() {
574
666
  return [this.name];
575
667
  }
668
+ get dataPath() {
669
+ return this.options.dataPath;
670
+ }
576
671
  /**
577
672
  * Indicates whether the visualizer displays a header. This property is `true` when a visualized question has a correct answer.
578
673
  * @see hasFooter
@@ -739,26 +834,9 @@ class VisualizerBase {
739
834
  * @param data A data array with survey results to be visualized.
740
835
  */
741
836
  updateData(data) {
742
- const dataPath = this.options.dataPath;
743
- let dataToAssign = data;
744
- if (!!dataPath && Array.isArray(data)) {
745
- dataToAssign = [];
746
- data.forEach(dataItem => {
747
- if (!!dataItem && dataItem[dataPath] !== undefined) {
748
- if (Array.isArray(dataItem[dataPath])) {
749
- dataToAssign = dataToAssign.concat(dataItem[dataPath]);
750
- }
751
- else {
752
- dataToAssign.push(dataItem[dataPath]);
753
- }
754
- }
755
- });
756
- }
757
- if (!this.options.dataProvider) {
758
- this.dataProvider.data = dataToAssign;
759
- }
837
+ this.dataProvider.data = data;
760
838
  if (this.hasFooter) {
761
- this.footerVisualizer.updateData(dataToAssign);
839
+ this.footerVisualizer.updateData(data);
762
840
  }
763
841
  }
764
842
  invokeOnUpdate() {
@@ -1297,7 +1375,7 @@ class NumberModel extends VisualizerBase {
1297
1375
  if (this._resultAverage === undefined ||
1298
1376
  this._resultMin === undefined ||
1299
1377
  this._resultMax === undefined) {
1300
- [this._resultAverage, this._resultMin, this._resultMax] = mathStatisticsCalculator(this.surveyData, this.dataNames[0]);
1378
+ [this._resultAverage, this._resultMin, this._resultMax] = mathStatisticsCalculator(this.surveyData, this);
1301
1379
  }
1302
1380
  return [this._resultAverage, this._resultMin, this._resultMax];
1303
1381
  }
@@ -1625,14 +1703,17 @@ class SelectBase extends VisualizerBase {
1625
1703
  return selBase.choices.filter((choice) => choice.text === itemText)[0];
1626
1704
  }
1627
1705
  }
1628
- setSelection(item) {
1706
+ onSelectionChanged(item) {
1629
1707
  var _a;
1708
+ if (this.onDataItemSelected !== undefined) {
1709
+ this.onDataItemSelected(item !== undefined ? item.value : undefined, item !== undefined ? item.text : "");
1710
+ }
1711
+ this.stateChanged("filter", (_a = this.selectedItem) === null || _a === void 0 ? void 0 : _a.value);
1712
+ }
1713
+ setSelection(item) {
1630
1714
  if (this.selectedItem !== item) {
1631
1715
  this.selectedItem = item;
1632
- if (this.onDataItemSelected !== undefined) {
1633
- this.onDataItemSelected(item !== undefined ? item.value : undefined, item !== undefined ? item.text : "");
1634
- }
1635
- this.stateChanged("filter", (_a = this.selectedItem) === null || _a === void 0 ? void 0 : _a.value);
1716
+ this.onSelectionChanged(item);
1636
1717
  }
1637
1718
  }
1638
1719
  get selection() {
@@ -1818,22 +1899,6 @@ class SelectBase extends VisualizerBase {
1818
1899
  }
1819
1900
  return percentages;
1820
1901
  }
1821
- answersDataReady(answersData) {
1822
- let result = {};
1823
- if (this.hideEmptyAnswers) {
1824
- result = hideEmptyAnswersInData(answersData);
1825
- }
1826
- else {
1827
- result = answersData;
1828
- }
1829
- if (this.topN > 0) {
1830
- result.datasets[0] = result.datasets[0].slice(-this.topN);
1831
- result.labels = result.labels.slice(-this.topN);
1832
- result.colors = result.colors.slice(-this.topN);
1833
- result.texts[0] = result.texts[0].slice(-this.topN);
1834
- }
1835
- return result;
1836
- }
1837
1902
  /**
1838
1903
  * Returns object with all infotmation for data visualization: datasets, labels, colors, additional texts (percentage).
1839
1904
  */
@@ -1869,7 +1934,15 @@ class SelectBase extends VisualizerBase {
1869
1934
  texts,
1870
1935
  seriesLabels,
1871
1936
  };
1872
- answersData = this.answersDataReady(answersData);
1937
+ if (this.hideEmptyAnswers) {
1938
+ answersData = hideEmptyAnswersInData(answersData);
1939
+ }
1940
+ if (this.topN > 0) {
1941
+ answersData.datasets[0] = answersData.datasets[0].slice(-this.topN);
1942
+ answersData.labels = answersData.labels.slice(-this.topN);
1943
+ answersData.colors = answersData.colors.slice(-this.topN);
1944
+ answersData.texts[0] = answersData.texts[0].slice(-this.topN);
1945
+ }
1873
1946
  this.onAnswersDataReady.fire(this, answersData);
1874
1947
  return answersData;
1875
1948
  });
@@ -2007,6 +2080,144 @@ BooleanModel.trueColor = "";
2007
2080
  BooleanModel.falseColor = "";
2008
2081
  VisualizationManager.registerVisualizer("boolean", BooleanModel);
2009
2082
 
2083
+ function getQuarter(date) {
2084
+ switch (Math.floor(date.getMonth() / 3) + 1) {
2085
+ case 1: return "I";
2086
+ case 2: return "II";
2087
+ case 3: return "III";
2088
+ case 4: return "IV";
2089
+ }
2090
+ }
2091
+ function getBestIntervalMode(min, max) {
2092
+ const start = new Date(min);
2093
+ const end = new Date(max);
2094
+ const totalMonths = (end.getFullYear() - start.getFullYear()) * 12 + (end.getMonth() - start.getMonth());
2095
+ if (totalMonths > 10 * 12)
2096
+ return "decades";
2097
+ if (totalMonths > 2 * 12)
2098
+ return "years";
2099
+ if (totalMonths > 1 * 12)
2100
+ return "quarters";
2101
+ if (totalMonths > 4)
2102
+ return "months";
2103
+ return "days";
2104
+ }
2105
+ const intervalCalculators = {
2106
+ decades: (min, max) => {
2107
+ const intervals = [];
2108
+ let start = new Date(min);
2109
+ start.setFullYear(Math.floor(start.getFullYear() / 10) * 10);
2110
+ start.setMonth(0);
2111
+ start.setDate(1);
2112
+ start.setHours(0, 0, 0, 0);
2113
+ let startYear = start.getFullYear();
2114
+ const end = new Date(max);
2115
+ const endYear = end.getFullYear();
2116
+ while (startYear <= endYear) {
2117
+ const intervalStart = new Date(startYear, 0, 1);
2118
+ const intervalEnd = new Date(startYear + 10, 0, 1);
2119
+ intervals.push({
2120
+ start: intervalStart.getTime(),
2121
+ end: intervalEnd.getTime(),
2122
+ label: "" + startYear + "s"
2123
+ });
2124
+ startYear += 10;
2125
+ }
2126
+ return intervals;
2127
+ },
2128
+ years: (min, max) => {
2129
+ const intervals = [];
2130
+ let start = new Date(min);
2131
+ start.setMonth(0);
2132
+ start.setDate(1);
2133
+ start.setHours(0, 0, 0, 0);
2134
+ let startYear = start.getFullYear();
2135
+ const end = new Date(max);
2136
+ const endYear = end.getFullYear();
2137
+ while (startYear <= endYear) {
2138
+ const intervalStart = new Date(startYear, 0, 1);
2139
+ const intervalEnd = new Date(startYear + 1, 0, 1);
2140
+ intervals.push({
2141
+ start: intervalStart.getTime(),
2142
+ end: intervalEnd.getTime(),
2143
+ label: "" + startYear
2144
+ });
2145
+ startYear++;
2146
+ }
2147
+ return intervals;
2148
+ },
2149
+ months: (min, max) => {
2150
+ const intervals = [];
2151
+ let start = new Date(min);
2152
+ start.setDate(1);
2153
+ start.setHours(0, 0, 0, 0);
2154
+ let startYear = start.getFullYear();
2155
+ let startMonth = start.getMonth();
2156
+ const end = new Date(max);
2157
+ const endYear = end.getFullYear();
2158
+ const endMonth = end.getMonth();
2159
+ while (startYear < endYear || (startYear === endYear && startMonth <= endMonth)) {
2160
+ const intervalStart = new Date(startYear, startMonth, 1);
2161
+ const intervalEnd = new Date(startYear, startMonth + 1, 1);
2162
+ intervals.push({
2163
+ start: intervalStart.getTime(),
2164
+ end: intervalEnd.getTime(),
2165
+ label: intervalStart.toLocaleDateString(undefined, { year: "numeric", month: "short" })
2166
+ });
2167
+ startMonth++;
2168
+ if (startMonth >= 12) {
2169
+ startMonth = 0;
2170
+ startYear++;
2171
+ }
2172
+ }
2173
+ return intervals;
2174
+ },
2175
+ quarters: (min, max) => {
2176
+ const intervals = [];
2177
+ let start = new Date(min);
2178
+ start.setDate(1);
2179
+ start.setHours(0, 0, 0, 0);
2180
+ let startYear = start.getFullYear();
2181
+ let startMonth = start.getMonth();
2182
+ const end = new Date(max);
2183
+ const endYear = end.getFullYear();
2184
+ const endMonth = end.getMonth();
2185
+ while (startYear < endYear || (startYear === endYear && startMonth <= endMonth)) {
2186
+ const intervalStart = new Date(startYear, startMonth, 1);
2187
+ const intervalEnd = new Date(startYear, startMonth + 3, 1);
2188
+ intervals.push({
2189
+ start: intervalStart.getTime(),
2190
+ end: intervalEnd.getTime(),
2191
+ label: getQuarter(intervalStart) + " " + intervalStart.getFullYear().toString()
2192
+ });
2193
+ startMonth += 3;
2194
+ if (startMonth >= 12) {
2195
+ startMonth = startMonth % 12;
2196
+ startYear++;
2197
+ }
2198
+ }
2199
+ return intervals;
2200
+ },
2201
+ days: (min, max) => {
2202
+ const intervals = [];
2203
+ let start = new Date(min);
2204
+ start.setHours(0, 0, 0, 0);
2205
+ const end = new Date(max);
2206
+ end.setHours(0, 0, 0, 0);
2207
+ while (start <= end) {
2208
+ const intervalStart = new Date(start);
2209
+ const intervalEnd = new Date(start);
2210
+ intervalEnd.setDate(intervalEnd.getDate() + 1);
2211
+ intervals.push({
2212
+ start: intervalStart.getTime(),
2213
+ end: intervalEnd.getTime(),
2214
+ label: intervalStart.toLocaleDateString()
2215
+ });
2216
+ start.setDate(start.getDate() + 1);
2217
+ }
2218
+ return intervals;
2219
+ }
2220
+ };
2010
2221
  class HistogramModel extends SelectBase {
2011
2222
  constructor(question, data, options, name) {
2012
2223
  super(question, data, options, name || "histogram");
@@ -2015,6 +2226,14 @@ class HistogramModel extends SelectBase {
2015
2226
  this._continuousData = undefined;
2016
2227
  this._cachedIntervals = undefined;
2017
2228
  this._intervalPrecision = 2;
2229
+ this.showRunningTotalsBtn = undefined;
2230
+ this.showGroupedBtn = undefined;
2231
+ this.changeIntervalsModeSelector = undefined;
2232
+ this.aggregateDataNameSelector = undefined;
2233
+ this.intervalModes = ["auto", "decades", "years", "quarters", "months", "days"];
2234
+ this._showRunningTotals = false;
2235
+ this._showGrouped = false;
2236
+ this._aggregateDataName = "";
2018
2237
  this._transposeData = false;
2019
2238
  if (this.options.intervalPrecision !== undefined) {
2020
2239
  this._intervalPrecision = this.options.intervalPrecision;
@@ -2026,6 +2245,61 @@ class HistogramModel extends SelectBase {
2026
2245
  else {
2027
2246
  this.valueType = "number";
2028
2247
  }
2248
+ this._intervalsMode = this.valueType === "date" ? "auto" : "default";
2249
+ if (this.allowChangeIntervals) {
2250
+ this.registerToolbarItem("changeIntervalsMode", () => {
2251
+ this.changeIntervalsModeSelector = DocumentHelper.createSelector(this.intervalModes.map((intervalModeValue) => {
2252
+ return {
2253
+ value: intervalModeValue,
2254
+ text: localization.getString("intervalMode_" + intervalModeValue),
2255
+ };
2256
+ }), (option) => this.intervalsMode === option.value, (e) => {
2257
+ this.intervalsMode = e.target.value;
2258
+ }, localization.getString("intervalModeTitle"));
2259
+ return this.changeIntervalsModeSelector;
2260
+ });
2261
+ }
2262
+ if (this.possibleAggregateDataNames.length > 0) {
2263
+ this.registerToolbarItem("aggregateDataName", () => {
2264
+ const choices = this.possibleAggregateDataNames.map((dataName) => {
2265
+ return typeof dataName === "string" ? { value: dataName, text: dataName } : dataName;
2266
+ });
2267
+ choices.unshift({ value: "", text: localization.getString("noneAggregateText") }),
2268
+ this.aggregateDataNameSelector = DocumentHelper.createSelector(choices, (option) => this.aggregateDataName === option.value, (e) => {
2269
+ this.aggregateDataName = e.target.value;
2270
+ }, localization.getString("selectAggregateText"));
2271
+ this.updateAggregateDataNameSelector();
2272
+ return this.aggregateDataNameSelector;
2273
+ });
2274
+ }
2275
+ if (this.allowChangeIntervals && this.options.allowRunningTotals) {
2276
+ this.registerToolbarItem("showRunningTotals", () => {
2277
+ this.showRunningTotalsBtn = DocumentHelper.createButton(() => {
2278
+ this.showRunningTotals = !this.showRunningTotals;
2279
+ });
2280
+ this.updateShowRunningTotalsBtn();
2281
+ return this.showRunningTotalsBtn;
2282
+ });
2283
+ }
2284
+ if (this.allowChangeIntervals && this.options.allowCompareDatePeriods) {
2285
+ this.registerToolbarItem("showGrouped", () => {
2286
+ this.showGroupedBtn = DocumentHelper.createButton(() => {
2287
+ this.showGrouped = !this.showGrouped;
2288
+ });
2289
+ this.updateShowGroupedBtn();
2290
+ return this.showGroupedBtn;
2291
+ });
2292
+ }
2293
+ }
2294
+ updateIntervalsModeSelector() {
2295
+ if (!!this.changeIntervalsModeSelector) {
2296
+ this.changeIntervalsModeSelector.getElementsByTagName("select")[0].value = this.intervalsMode;
2297
+ }
2298
+ }
2299
+ updateAggregateDataNameSelector() {
2300
+ if (!!this.aggregateDataNameSelector) {
2301
+ this.aggregateDataNameSelector.getElementsByTagName("select")[0].value = this.aggregateDataName;
2302
+ }
2029
2303
  }
2030
2304
  reset() {
2031
2305
  this._continuousData = undefined;
@@ -2068,6 +2342,17 @@ class HistogramModel extends SelectBase {
2068
2342
  this.reset();
2069
2343
  super.onDataChanged();
2070
2344
  }
2345
+ onSelectionChanged(item) {
2346
+ if (item !== undefined && this.onDataItemSelected !== undefined) {
2347
+ if (this.valueType === "date") {
2348
+ const currIntervalCalueIndex = this.intervalModes.indexOf(this.intervalsMode);
2349
+ if (currIntervalCalueIndex > 0 && currIntervalCalueIndex < this.intervalModes.length - 1) {
2350
+ this.intervalsMode = this.intervalModes[currIntervalCalueIndex + 1];
2351
+ }
2352
+ }
2353
+ }
2354
+ super.onSelectionChanged(item);
2355
+ }
2071
2356
  getContinuousValues() {
2072
2357
  if (this._cachedValues === undefined) {
2073
2358
  const series = this.getSeriesValues();
@@ -2077,20 +2362,26 @@ class HistogramModel extends SelectBase {
2077
2362
  this._continuousData = {};
2078
2363
  series.forEach(seriesValue => this._continuousData[seriesValue] = []);
2079
2364
  const hash = {};
2080
- this.data.forEach(dataItem => {
2081
- const answerData = dataItem[this.name];
2082
- if (answerData !== undefined) {
2083
- const seriesValue = dataItem[DataProvider.seriesMarkerKey] || "";
2084
- // TODO: _continuousData should be sorted in order to speed-up statistics calculation in the getData function
2085
- this._continuousData[seriesValue].push(this.getContinuousValue(answerData));
2086
- hash[answerData] = answerData;
2087
- }
2365
+ this.data.forEach(dataRow => {
2366
+ const nestedDataRows = getNestedDataRows(dataRow, this);
2367
+ nestedDataRows.forEach(nestedDataRow => {
2368
+ const answerData = nestedDataRow[this.dataNames[0]];
2369
+ if (answerData !== undefined) {
2370
+ const seriesValue = nestedDataRow[DataProvider.seriesMarkerKey] || "";
2371
+ // TODO: _continuousData should be sorted in order to speed-up statistics calculation in the getData function
2372
+ this._continuousData[seriesValue].push({ continuous: this.getContinuousValue(answerData), row: nestedDataRow });
2373
+ hash[answerData] = answerData;
2374
+ }
2375
+ });
2088
2376
  });
2089
- this._cachedValues = Object.keys(hash).map(key => ({ original: hash[key], continuous: this.getContinuousValue(key) }));
2377
+ this._cachedValues = Object.keys(hash).map(key => ({ original: hash[key], continuous: this.getContinuousValue(key), row: hash[key].row }));
2090
2378
  this._cachedValues.sort((a, b) => a.continuous - b.continuous);
2091
2379
  }
2092
2380
  return this._cachedValues;
2093
2381
  }
2382
+ isSupportSoftUpdateContent() {
2383
+ return false;
2384
+ }
2094
2385
  isSupportMissingAnswers() {
2095
2386
  return false;
2096
2387
  }
@@ -2138,29 +2429,220 @@ class HistogramModel extends SelectBase {
2138
2429
  if (continuousValues.length) {
2139
2430
  let start = continuousValues[0].continuous;
2140
2431
  const end = continuousValues[continuousValues.length - 1].continuous;
2141
- const intervalsCount = HistogramModel.IntervalsCount;
2142
- const delta = (end - start) / intervalsCount;
2143
- for (let i = 0; i < intervalsCount; ++i) {
2144
- const next = start + delta;
2145
- const istart = this.toPrecision(start);
2146
- const inext = this.toPrecision(next);
2147
- this._cachedIntervals.push({
2148
- start: istart,
2149
- end: i < intervalsCount - 1 ? inext : inext + delta / 100,
2150
- label: "" + this.getString(istart) + "-" + this.getString(inext)
2151
- });
2152
- start = next;
2432
+ const intervalsMode = this.intervalsMode === "auto" ? getBestIntervalMode(start, end) : this.intervalsMode;
2433
+ if (intervalCalculators[intervalsMode] !== undefined) {
2434
+ this._cachedIntervals = intervalCalculators[intervalsMode](start, end);
2435
+ }
2436
+ else {
2437
+ const intervalsCount = HistogramModel.IntervalsCount;
2438
+ const delta = (end - start) / intervalsCount;
2439
+ for (let i = 0; i < intervalsCount; ++i) {
2440
+ const next = start + delta;
2441
+ const istart = this.toPrecision(start);
2442
+ const inext = this.toPrecision(next);
2443
+ this._cachedIntervals.push({
2444
+ start: istart,
2445
+ end: i < intervalsCount - 1 ? inext : inext + delta / 100,
2446
+ label: "" + this.getString(istart) + "-" + this.getString(inext)
2447
+ });
2448
+ start = next;
2449
+ }
2153
2450
  }
2154
2451
  }
2155
2452
  }
2156
2453
  return this._cachedIntervals;
2157
2454
  }
2455
+ get intervalsMode() {
2456
+ if (this.hasCustomIntervals)
2457
+ return "custom";
2458
+ return this._intervalsMode;
2459
+ }
2460
+ set intervalsMode(val) {
2461
+ if (this.allowChangeIntervals && this._intervalsMode !== val) {
2462
+ this._intervalsMode = val;
2463
+ if (!this.canShowGroupedDateSeries) {
2464
+ this._showGrouped = false;
2465
+ }
2466
+ this.updateIntervalsModeSelector();
2467
+ this.updateShowGroupedBtn();
2468
+ this.onDataChanged();
2469
+ }
2470
+ }
2471
+ get allowChangeIntervals() {
2472
+ return this.valueType === "date" && !this.hasCustomIntervals && this.options.allowChangeIntervals === true;
2473
+ }
2474
+ get showRunningTotals() {
2475
+ return this._showRunningTotals;
2476
+ }
2477
+ set showRunningTotals(val) {
2478
+ this._showRunningTotals = val;
2479
+ this.updateShowRunningTotalsBtn();
2480
+ this.stateChanged("showRunningTotals", val);
2481
+ this.refreshContent();
2482
+ }
2483
+ updateShowRunningTotalsBtn() {
2484
+ if (!!this.showRunningTotalsBtn) {
2485
+ this.showRunningTotalsBtn.innerText = this.showRunningTotals
2486
+ ? localization.getString("noRunningTotals")
2487
+ : localization.getString("runningTotals");
2488
+ }
2489
+ }
2490
+ get showGrouped() {
2491
+ return this._showGrouped;
2492
+ }
2493
+ set showGrouped(val) {
2494
+ this._showGrouped = val;
2495
+ this.updateShowGroupedBtn();
2496
+ this.stateChanged("showGrouped", val);
2497
+ this.refreshContent();
2498
+ }
2499
+ updateShowGroupedBtn() {
2500
+ if (!!this.showGroupedBtn) {
2501
+ this.showGroupedBtn.innerText = this.showGrouped
2502
+ ? localization.getString("ungroupDateSeries")
2503
+ : localization.getString("groupDateSeries");
2504
+ this.showGroupedBtn.style.display = this.canShowGroupedDateSeries ? "inline" : "none";
2505
+ }
2506
+ }
2507
+ get canShowGroupedDateSeries() {
2508
+ return ["years", "quarters", "months"].indexOf(this.intervalsMode) !== -1;
2509
+ }
2510
+ get aggregateDataName() {
2511
+ return this._aggregateDataName;
2512
+ }
2513
+ set aggregateDataName(val) {
2514
+ if (this._aggregateDataName !== val) {
2515
+ this._aggregateDataName = val;
2516
+ this.onDataChanged();
2517
+ }
2518
+ }
2519
+ get possibleAggregateDataNames() {
2520
+ var _a, _b;
2521
+ return (_b = (_a = this.questionOptions) === null || _a === void 0 ? void 0 : _a.aggregateDataNames) !== null && _b !== void 0 ? _b : [];
2522
+ }
2158
2523
  convertFromExternalData(externalCalculatedData) {
2159
2524
  return [externalCalculatedData];
2160
2525
  }
2161
2526
  getCalculatedValuesCore() {
2162
2527
  this.getContinuousValues();
2163
- return histogramStatisticsCalculator(this._continuousData, this.intervals, this.getSeriesValues());
2528
+ return histogramStatisticsCalculator(this._continuousData, this.intervals, this, [this.aggregateDataName].filter(name => !!name));
2529
+ }
2530
+ getCalculatedValues() {
2531
+ const _super = Object.create(null, {
2532
+ getCalculatedValues: { get: () => super.getCalculatedValues }
2533
+ });
2534
+ return __awaiter(this, void 0, void 0, function* () {
2535
+ const values = yield _super.getCalculatedValues.call(this);
2536
+ const result = JSON.parse(JSON.stringify(values));
2537
+ if (this.showRunningTotals) {
2538
+ for (let i = 0; i < result.length; i++) {
2539
+ for (let j = 1; j < result[i].length; j++) {
2540
+ result[i][j] += result[i][j - 1];
2541
+ }
2542
+ }
2543
+ }
2544
+ return result;
2545
+ });
2546
+ }
2547
+ getGroupedDateAnswersData() {
2548
+ return __awaiter(this, void 0, void 0, function* () {
2549
+ let datasets = (yield this.getCalculatedValues());
2550
+ let colors = this.getColors();
2551
+ let labels = this.getLabels();
2552
+ let seriesLabels = this.getSeriesLabels();
2553
+ const intervals = [].concat(this.intervals);
2554
+ const start = new Date(intervals[0].start);
2555
+ const end = new Date(intervals[intervals.length - 1].end);
2556
+ const startYear = start.getFullYear();
2557
+ const endYear = end.getFullYear();
2558
+ if (this.intervalsMode === "years") {
2559
+ seriesLabels = [];
2560
+ const groupedDatasets = [];
2561
+ for (let year = Math.floor(startYear / 10) * 10; year <= endYear; year += 10) {
2562
+ seriesLabels.push(year.toString() + "s");
2563
+ groupedDatasets.push(new Array(10).fill(0));
2564
+ }
2565
+ for (let i = 0; i < intervals.length; i++) {
2566
+ const interval = intervals[i];
2567
+ const intervalDate = new Date(interval.start);
2568
+ const decade = Math.floor(intervalDate.getFullYear() / 10) * 10;
2569
+ const yearInDecade = intervalDate.getFullYear() - decade;
2570
+ const decadeIndex = Math.floor((decade - Math.floor(startYear / 10) * 10) / 10);
2571
+ groupedDatasets[decadeIndex][yearInDecade] = datasets[0][i];
2572
+ }
2573
+ datasets = groupedDatasets;
2574
+ labels = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
2575
+ }
2576
+ else if (this.intervalsMode === "quarters") {
2577
+ seriesLabels = [];
2578
+ const groupedDatasets = [];
2579
+ for (let year = startYear; year <= endYear; year++) {
2580
+ seriesLabels.push(year.toString());
2581
+ groupedDatasets.push(new Array(4).fill(0));
2582
+ }
2583
+ for (let i = 0; i < intervals.length; i++) {
2584
+ const interval = intervals[i];
2585
+ const intervalDate = new Date(interval.start);
2586
+ const quarter = Math.floor(intervalDate.getMonth() / 3);
2587
+ const year = intervalDate.getFullYear();
2588
+ const yearIndex = year - startYear;
2589
+ groupedDatasets[yearIndex][quarter] = datasets[0][i];
2590
+ }
2591
+ datasets = groupedDatasets;
2592
+ labels = ["I", "II", "III", "IV"];
2593
+ }
2594
+ else if (this.intervalsMode === "months") {
2595
+ seriesLabels = [];
2596
+ const groupedDatasets = [];
2597
+ for (let year = startYear; year <= endYear; year++) {
2598
+ seriesLabels.push(year.toString());
2599
+ groupedDatasets.push(new Array(12).fill(0));
2600
+ }
2601
+ for (let i = 0; i < intervals.length; i++) {
2602
+ const interval = intervals[i];
2603
+ const intervalDate = new Date(interval.start);
2604
+ const month = intervalDate.getMonth();
2605
+ const year = intervalDate.getFullYear();
2606
+ const yearIndex = year - startYear;
2607
+ groupedDatasets[yearIndex][month] = datasets[0][i];
2608
+ }
2609
+ datasets = groupedDatasets;
2610
+ labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
2611
+ }
2612
+ let texts = datasets;
2613
+ return {
2614
+ datasets,
2615
+ labels,
2616
+ colors,
2617
+ texts,
2618
+ seriesLabels,
2619
+ };
2620
+ });
2621
+ }
2622
+ /**
2623
+ * Returns object with all infotmation for data visualization: datasets, labels, colors, additional texts (percentage).
2624
+ */
2625
+ getAnswersData() {
2626
+ const _super = Object.create(null, {
2627
+ getAnswersData: { get: () => super.getAnswersData }
2628
+ });
2629
+ return __awaiter(this, void 0, void 0, function* () {
2630
+ if (!this.showGrouped) {
2631
+ return _super.getAnswersData.call(this);
2632
+ }
2633
+ const answersData = yield this.getGroupedDateAnswersData();
2634
+ const continuousValues = this.getContinuousValues();
2635
+ if (continuousValues.length) {
2636
+ let start = continuousValues[0].continuous;
2637
+ const end = continuousValues[continuousValues.length - 1].continuous;
2638
+ const intervalsMode = this.intervalsMode === "auto" ? getBestIntervalMode(start, end) : this.intervalsMode;
2639
+ if (intervalsMode === "years" && this.showGrouped) {
2640
+ answersData.labelsTitle = localization.getString("groupedYearsAxisTitle");
2641
+ }
2642
+ }
2643
+ this.onAnswersDataReady.fire(this, answersData);
2644
+ return answersData;
2645
+ });
2164
2646
  }
2165
2647
  getValueType() {
2166
2648
  return this.valueType;
@@ -9823,6 +10305,50 @@ class MuuriLayoutEngine extends LayoutEngine {
9823
10305
  }
9824
10306
  }
9825
10307
 
10308
+ class VisualizationPanelDynamic extends VisualizerBase {
10309
+ constructor(question, data, options = {}, name) {
10310
+ super(question, data, options, name || "panelDynamic");
10311
+ this._contentVisualizer = undefined;
10312
+ this.onAfterRenderPanelCallback = () => {
10313
+ this.afterRender(this.contentContainer);
10314
+ };
10315
+ this.loadingData = false;
10316
+ var options = Object.assign({}, options);
10317
+ options.allowHideQuestions = false;
10318
+ options.allowDynamicLayout = false;
10319
+ options.dataProvider = this.dataProvider;
10320
+ options.dataPath = this.dataNames[0];
10321
+ this._contentVisualizer = new VisualizationPanel(this.getQuestions(), [], options, undefined, false);
10322
+ this._contentVisualizer.onAfterRender.add(this.onAfterRenderPanelCallback);
10323
+ }
10324
+ get contentVisualizer() {
10325
+ return this._contentVisualizer;
10326
+ }
10327
+ setLocale(newLocale) {
10328
+ super.setLocale(newLocale);
10329
+ this._contentVisualizer.locale = newLocale;
10330
+ }
10331
+ resetFilter() {
10332
+ this.contentVisualizer.resetFilter();
10333
+ }
10334
+ getQuestions() {
10335
+ const paneldynamic = this.question;
10336
+ return paneldynamic.template.questions;
10337
+ }
10338
+ destroyContent(container) {
10339
+ this._contentVisualizer.clear();
10340
+ super.destroyContent(this.contentContainer);
10341
+ }
10342
+ renderContent(container) {
10343
+ this._contentVisualizer.render(container);
10344
+ }
10345
+ destroy() {
10346
+ super.destroy();
10347
+ this._contentVisualizer.onAfterRender.remove(this.onAfterRenderPanelCallback);
10348
+ }
10349
+ }
10350
+ VisualizationManager.registerVisualizer("paneldynamic", VisualizationPanelDynamic);
10351
+
9826
10352
  const questionElementClassName = "sa-question";
9827
10353
  const questionLayoutedElementClassName = "sa-question-layouted";
9828
10354
  if (!!document) {
@@ -9855,7 +10381,7 @@ class VisualizationPanel extends VisualizerBase {
9855
10381
  this.renderedQuestionsCount = 0;
9856
10382
  this.onAfterRenderQuestionCallback = (sender, options) => {
9857
10383
  this.renderedQuestionsCount++;
9858
- if (this.renderedQuestionsCount == this.questions.length) {
10384
+ if (this.renderedQuestionsCount == this.visibleElements.length) {
9859
10385
  this.renderedQuestionsCount = 0;
9860
10386
  this.layoutEngine.update();
9861
10387
  this.afterRender(this.contentContainer);
@@ -9942,7 +10468,6 @@ class VisualizationPanel extends VisualizerBase {
9942
10468
  this._elements = this.buildElements(questions);
9943
10469
  }
9944
10470
  this.buildVisualizers(questions);
9945
- this.updateData(this.surveyData);
9946
10471
  if (!this.haveCommercialLicense && this.isRoot) {
9947
10472
  this.registerToolbarItem("commercialLicense", () => {
9948
10473
  return createCommercialLicenseLink();
@@ -9952,11 +10477,7 @@ class VisualizationPanel extends VisualizerBase {
9952
10477
  if (this.supportSelection !== false) {
9953
10478
  this.registerToolbarItem("resetFilter", () => {
9954
10479
  return DocumentHelper.createButton(() => {
9955
- this.visualizers.forEach((visualizer) => {
9956
- if (visualizer instanceof SelectBase || visualizer instanceof AlternativeVisualizersWrapper) {
9957
- visualizer.setSelection(undefined);
9958
- }
9959
- });
10480
+ this.resetFilter();
9960
10481
  }, localization.getString("resetFilter"));
9961
10482
  }, 900);
9962
10483
  }
@@ -10016,6 +10537,18 @@ class VisualizationPanel extends VisualizerBase {
10016
10537
  });
10017
10538
  }
10018
10539
  }
10540
+ resetFilter() {
10541
+ var _a;
10542
+ (_a = this.dataProvider) === null || _a === void 0 ? void 0 : _a.resetFilter();
10543
+ this.visualizers.forEach((visualizer) => {
10544
+ if (visualizer instanceof SelectBase || visualizer instanceof AlternativeVisualizersWrapper) {
10545
+ visualizer.setSelection(undefined);
10546
+ }
10547
+ if (visualizer instanceof VisualizationPanelDynamic) {
10548
+ visualizer.resetFilter();
10549
+ }
10550
+ });
10551
+ }
10019
10552
  reorderVisibleElements(order) {
10020
10553
  const newElements = [];
10021
10554
  order.forEach(name => {
@@ -10117,13 +10650,15 @@ class VisualizationPanel extends VisualizerBase {
10117
10650
  buildVisualizers(questions) {
10118
10651
  questions.forEach((question) => {
10119
10652
  let visualizerOptions = Object.assign({}, this.options);
10120
- let visualizerData = this.surveyData;
10653
+ if (visualizerOptions.dataProvider === undefined) {
10654
+ visualizerOptions.dataProvider = this.dataProvider;
10655
+ }
10121
10656
  let visualizer;
10122
10657
  if (Array.isArray(question)) {
10123
- visualizer = new (VisualizationManager.getPivotVisualizerConstructor())(question, visualizerData, visualizerOptions, undefined, false);
10658
+ visualizer = new (VisualizationManager.getPivotVisualizerConstructor())(question, [], visualizerOptions, undefined, false);
10124
10659
  }
10125
10660
  else {
10126
- visualizer = this.createVisualizer(question, visualizerOptions, visualizerData);
10661
+ visualizer = this.createVisualizer(question, visualizerOptions, []);
10127
10662
  }
10128
10663
  if (!visualizer) {
10129
10664
  return;
@@ -10409,7 +10944,23 @@ class VisualizationPanel extends VisualizerBase {
10409
10944
  * @see IVisualizationPanelOptions.allowSelection
10410
10945
  */
10411
10946
  setFilter(questionName, selectedValue) {
10412
- this.dataProvider.setFilter(questionName, selectedValue);
10947
+ if (!this.dataPath) {
10948
+ this.dataProvider.setFilter(questionName, selectedValue);
10949
+ }
10950
+ else {
10951
+ if (selectedValue !== undefined && selectedValue !== null) {
10952
+ if (typeof selectedValue === "object" && Object.keys(selectedValue)[0]) {
10953
+ const seriesValue = Object.keys(selectedValue)[0];
10954
+ this.dataProvider.setFilter(this.dataPath, { [questionName]: selectedValue[seriesValue], [DataProvider.seriesMarkerKey]: seriesValue });
10955
+ }
10956
+ else {
10957
+ this.dataProvider.setFilter(this.dataPath, { [questionName]: selectedValue });
10958
+ }
10959
+ }
10960
+ else {
10961
+ this.dataProvider.setFilter(this.dataPath, undefined);
10962
+ }
10963
+ }
10413
10964
  }
10414
10965
  getState() {
10415
10966
  return {
@@ -10498,56 +11049,6 @@ class VisualizationPanel extends VisualizerBase {
10498
11049
  }
10499
11050
  }
10500
11051
 
10501
- class VisualizationPanelDynamic extends VisualizerBase {
10502
- constructor(question, data, options = {}, name) {
10503
- super(question, data, options, name || "panelDynamic");
10504
- this._panelVisualizer = undefined;
10505
- this.onAfterRenderPanelCallback = () => {
10506
- this.afterRender(this.contentContainer);
10507
- };
10508
- this.loadingData = false;
10509
- var options = Object.assign({}, options);
10510
- options.allowHideQuestions = false;
10511
- options.allowDynamicLayout = false;
10512
- options.dataProvider = undefined;
10513
- options.dataPath = this.dataNames[0];
10514
- this._panelVisualizer = new VisualizationPanel(this.getQuestions(), [], options, undefined, false);
10515
- this._panelVisualizer.onAfterRender.add(this.onAfterRenderPanelCallback);
10516
- this.updateData(data);
10517
- }
10518
- get contentVisualizer() {
10519
- return this._panelVisualizer;
10520
- }
10521
- setLocale(newLocale) {
10522
- super.setLocale(newLocale);
10523
- this._panelVisualizer.locale = newLocale;
10524
- }
10525
- updateData(data) {
10526
- super.updateData(data);
10527
- this._panelVisualizer.updateData(data);
10528
- }
10529
- onDataChanged() {
10530
- this._panelVisualizer.updateData(this.dataProvider.filteredData);
10531
- super.onDataChanged();
10532
- }
10533
- getQuestions() {
10534
- const paneldynamic = this.question;
10535
- return paneldynamic.template.questions;
10536
- }
10537
- destroyContent(container) {
10538
- this._panelVisualizer.clear();
10539
- super.destroyContent(this.contentContainer);
10540
- }
10541
- renderContent(container) {
10542
- this._panelVisualizer.render(container);
10543
- }
10544
- destroy() {
10545
- super.destroy();
10546
- this._panelVisualizer.onAfterRender.remove(this.onAfterRenderPanelCallback);
10547
- }
10548
- }
10549
- VisualizationManager.registerVisualizer("paneldynamic", VisualizationPanelDynamic);
10550
-
10551
11052
  class VisualizationMatrixDynamic extends VisualizationPanelDynamic {
10552
11053
  constructor(question, data, options, name) {
10553
11054
  super(question, data, options, name || "matrixDynamic");
@@ -10576,28 +11077,29 @@ function isChoicesArraysEqual(choices1, choices2) {
10576
11077
  class VisualizationMatrixDropdown extends VisualizerBase {
10577
11078
  constructor(question, data, options = {}, name) {
10578
11079
  super(question, data, options, name || "matrixDropdown");
10579
- this._matrixDropdownVisualizer = undefined;
11080
+ this._contentVisualizer = undefined;
10580
11081
  this.onPanelAfterRenderCallback = () => {
10581
11082
  this.afterRender(this.contentContainer);
10582
11083
  };
10583
11084
  this.loadingData = false;
10584
11085
  this._childOptions = Object.assign({}, options);
10585
11086
  this._childOptions.disableLocaleSwitch = true;
10586
- this._childOptions.dataProvider = undefined;
10587
11087
  this._childOptions.allowDynamicLayout = false;
10588
11088
  this._childOptions.transposeData = true;
11089
+ this._childOptions.dataProvider = this.dataProvider;
11090
+ this._childOptions.dataPath = this.dataNames[0];
10589
11091
  this._childOptions.seriesValues = question.rows.map((row) => row.value);
10590
11092
  this._childOptions.seriesLabels = question.rows.map((row) => row.text);
11093
+ this.dataProvider.fixDropdownData(this.dataNames);
10591
11094
  if (this.canGroupColumns) {
10592
11095
  var creators = VisualizationManager.getVisualizersByType("matrixdropdown-grouped");
10593
- this._matrixDropdownVisualizer = new creators[0](this.question, [], this._childOptions);
11096
+ this._contentVisualizer = new creators[0](this.question, [], this._childOptions);
10594
11097
  }
10595
11098
  else {
10596
11099
  const innerQuestions = this.getQuestions();
10597
- this._matrixDropdownVisualizer = new VisualizationPanel(innerQuestions, [], this._childOptions, undefined, false);
11100
+ this._contentVisualizer = new VisualizationPanel(innerQuestions, [], this._childOptions, undefined, false);
10598
11101
  }
10599
- this._matrixDropdownVisualizer.onAfterRender.add(this.onPanelAfterRenderCallback);
10600
- this.updateData(data);
11102
+ this._contentVisualizer.onAfterRender.add(this.onPanelAfterRenderCallback);
10601
11103
  }
10602
11104
  get canGroupColumns() {
10603
11105
  const innerQuestions = this.getQuestions();
@@ -10607,32 +11109,14 @@ class VisualizationMatrixDropdown extends VisualizerBase {
10607
11109
  setLocale(newLocale) {
10608
11110
  super.setLocale(newLocale);
10609
11111
  this._childOptions.seriesLabels = this.question.rows.map((row) => row.text);
10610
- this._matrixDropdownVisualizer.locale = newLocale;
10611
- }
10612
- get matrixDropdownVisualizer() {
10613
- return this._matrixDropdownVisualizer;
11112
+ this._contentVisualizer.locale = newLocale;
10614
11113
  }
10615
- updateDropdownVisualizerData() {
10616
- let panelData = [];
10617
- this.data.forEach((dataItem) => {
10618
- let rawDataItem = dataItem[this.question.name];
10619
- if (!!rawDataItem) {
10620
- Object.keys(rawDataItem).forEach((key) => {
10621
- var nestedDataItem = Object.assign({}, rawDataItem[key]);
10622
- nestedDataItem[DataProvider.seriesMarkerKey] = key;
10623
- panelData.push(nestedDataItem);
10624
- });
10625
- }
10626
- });
10627
- this._matrixDropdownVisualizer.updateData(panelData);
11114
+ get contentVisualizer() {
11115
+ return this._contentVisualizer;
10628
11116
  }
10629
11117
  updateData(data) {
10630
11118
  super.updateData(data);
10631
- this.updateDropdownVisualizerData();
10632
- }
10633
- onDataChanged() {
10634
- this.updateDropdownVisualizerData();
10635
- super.onDataChanged();
11119
+ this.dataProvider.fixDropdownData(this.dataNames);
10636
11120
  }
10637
11121
  getQuestions() {
10638
11122
  const matrixdropdown = this.question;
@@ -10645,15 +11129,15 @@ class VisualizationMatrixDropdown extends VisualizerBase {
10645
11129
  });
10646
11130
  }
10647
11131
  destroyContent(container) {
10648
- this._matrixDropdownVisualizer.clear();
11132
+ this._contentVisualizer.clear();
10649
11133
  super.destroyContent(this.contentContainer);
10650
11134
  }
10651
11135
  renderContent(container) {
10652
- this._matrixDropdownVisualizer.render(container);
11136
+ this._contentVisualizer.render(container);
10653
11137
  }
10654
11138
  destroy() {
10655
11139
  super.destroy();
10656
- this._matrixDropdownVisualizer.onAfterRender.remove(this.onPanelAfterRenderCallback);
11140
+ this._contentVisualizer.onAfterRender.remove(this.onPanelAfterRenderCallback);
10657
11141
  }
10658
11142
  }
10659
11143
  VisualizationManager.registerVisualizer("matrixdropdown", VisualizationMatrixDropdown);
@@ -12679,5 +13163,5 @@ NpsVisualizer.DetractorScore = 6;
12679
13163
  NpsVisualizer.PromoterScore = 9;
12680
13164
  // VisualizationManager.registerVisualizer("rating", NpsVisualizer);
12681
13165
 
12682
- export { AlternativeVisualizersWrapper as A, BooleanModel as B, DataProvider as D, HistogramModel as H, Matrix as M, NumberModel as N, PostponeHelper as P, RankingModel as R, SelectBase as S, TextTableAdapter as T, VisualizerFactory as V, WordCloudAdapter as W, __awaiter as _, VisualizerBase as a, VisualizationManager as b, VisualizationPanel as c, VisualizationPanelDynamic as d, VisualizationMatrixDynamic as e, VisualizationMatrixDropdown as f, VisualizationComposite as g, hideEmptyAnswersInData as h, WordCloud as i, Text as j, StatisticsTableAdapter as k, StatisticsTable as l, StatisticsTableBoolean as m, NpsVisualizerWidget as n, NpsAdapter as o, NpsVisualizer as p, PivotModel as q, defaultStatisticsCalculator as r, textHelper as t };
13166
+ export { AlternativeVisualizersWrapper as A, BooleanModel as B, DataProvider as D, HistogramModel as H, Matrix as M, NumberModel as N, PostponeHelper as P, RankingModel as R, SelectBase as S, TextTableAdapter as T, VisualizerFactory as V, WordCloudAdapter as W, __awaiter as _, VisualizerBase as a, VisualizationManager as b, VisualizationPanel as c, VisualizationPanelDynamic as d, VisualizationMatrixDynamic as e, VisualizationMatrixDropdown as f, getBestIntervalMode as g, hideEmptyAnswersInData as h, intervalCalculators as i, VisualizationComposite as j, WordCloud as k, Text as l, StatisticsTableAdapter as m, StatisticsTable as n, StatisticsTableBoolean as o, NpsVisualizerWidget as p, NpsAdapter as q, NpsVisualizer as r, PivotModel as s, textHelper as t, defaultStatisticsCalculator as u };
12683
13167
  //# sourceMappingURL=shared2.mjs.map