| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  | import ChartJs from "../Base/ChartJs"; | 
					
						
							|  |  |  | import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"; | 
					
						
							|  |  |  | import {ChartConfiguration} from 'chart.js'; | 
					
						
							|  |  |  | import Combine from "../Base/Combine"; | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  | import {TagUtils} from "../../Logic/Tags/TagUtils"; | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  | import {Utils} from "../../Utils"; | 
					
						
							|  |  |  | import {OsmFeature} from "../../Models/OsmFeature"; | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  | export interface TagRenderingChartOptions { | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |     groupToOtherCutoff?: 3 | number, | 
					
						
							|  |  |  |     sort?: boolean | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  | export class StackedRenderingChart extends ChartJs { | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |     constructor(tr: TagRenderingConfig, features: (OsmFeature & { properties: { date: string } })[], options?: { | 
					
						
							|  |  |  |         period: "day" | "month", | 
					
						
							|  |  |  |         groupToOtherCutoff?: 3 | number | 
					
						
							|  |  |  |     }) { | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  |         const {labels, data} = TagRenderingChart.extractDataAndLabels(tr, features, { | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |             sort: true, | 
					
						
							|  |  |  |             groupToOtherCutoff: options?.groupToOtherCutoff | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  |         }) | 
					
						
							|  |  |  |         if (labels === undefined || data === undefined) { | 
					
						
							|  |  |  |             throw ("No labels or data given...") | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // labels: ["cyclofix", "buurtnatuur", ...]; data : [ ["cyclofix-changeset", "cyclofix-changeset", ...], ["buurtnatuur-cs", "buurtnatuur-cs"], ... ]
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |          | 
					
						
							|  |  |  |         for (let i = labels.length; i >= 0; i--) { | 
					
						
							|  |  |  |             if (data[i]?.length != 0) { | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             data.splice(i, 1) | 
					
						
							|  |  |  |             labels.splice(i, 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const datasets: { label: string /*themename*/, data: number[]/*counts per day*/, backgroundColor: string }[] = [] | 
					
						
							|  |  |  |         const allDays = StackedRenderingChart.getAllDays(features) | 
					
						
							|  |  |  |         let trimmedDays = allDays.map(d => d.substr(0, d.indexOf("T"))) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |         if (options?.period === "month") { | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  |             trimmedDays = trimmedDays.map(d => d.substr(0, 7)) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         trimmedDays = Utils.Dedup(trimmedDays) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  |         for (let i = 0; i < labels.length; i++) { | 
					
						
							|  |  |  |             const label = labels[i]; | 
					
						
							|  |  |  |             const changesetsForTheme = data[i] | 
					
						
							|  |  |  |             const perDay: Record<string, OsmFeature[]> = {} | 
					
						
							|  |  |  |             for (const changeset of changesetsForTheme) { | 
					
						
							|  |  |  |                 const csDate = new Date(changeset.properties.date) | 
					
						
							|  |  |  |                 Utils.SetMidnight(csDate) | 
					
						
							|  |  |  |                 let str = csDate.toISOString(); | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |                 if (options?.period === "month") { | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  |                     csDate.setUTCDate(1) | 
					
						
							|  |  |  |                     str = csDate.toISOString().substr(0, 7); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (perDay[str] === undefined) { | 
					
						
							|  |  |  |                     perDay[str] = [changeset] | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     perDay[str].push(changeset) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const countsPerDay: number[] = [] | 
					
						
							|  |  |  |             for (let i = 0; i < trimmedDays.length; i++) { | 
					
						
							|  |  |  |                 const day = trimmedDays[i]; | 
					
						
							|  |  |  |                 countsPerDay[i] = perDay[day]?.length ?? 0 | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |             let backgroundColor = TagRenderingChart.borderColors[i % TagRenderingChart.borderColors.length] | 
					
						
							|  |  |  |             if (label === "Unknown") { | 
					
						
							|  |  |  |                 backgroundColor = TagRenderingChart.unkownBorderColor | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (label === "Other") { | 
					
						
							|  |  |  |                 backgroundColor = TagRenderingChart.otherBorderColor | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  |             datasets.push({ | 
					
						
							|  |  |  |                 data: countsPerDay, | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |                 backgroundColor, | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  |                 label | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  |         const perDayData = { | 
					
						
							|  |  |  |             labels: trimmedDays, | 
					
						
							|  |  |  |             datasets | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const config = <ChartConfiguration>{ | 
					
						
							|  |  |  |             type: 'bar', | 
					
						
							|  |  |  |             data: perDayData, | 
					
						
							|  |  |  |             options: { | 
					
						
							|  |  |  |                 responsive: true, | 
					
						
							|  |  |  |                 legend: { | 
					
						
							|  |  |  |                     display: false | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 scales: { | 
					
						
							|  |  |  |                     x: { | 
					
						
							|  |  |  |                         stacked: true, | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     y: { | 
					
						
							|  |  |  |                         stacked: true | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         super(config) | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |     public static getAllDays(features: (OsmFeature & { properties: { date: string } })[]): string[] { | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  |         let earliest: Date = undefined | 
					
						
							|  |  |  |         let latest: Date = undefined; | 
					
						
							|  |  |  |         let allDates = new Set<string>(); | 
					
						
							|  |  |  |         features.forEach((value, key) => { | 
					
						
							|  |  |  |             const d = new Date(value.properties.date); | 
					
						
							|  |  |  |             Utils.SetMidnight(d) | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  |             if (earliest === undefined) { | 
					
						
							|  |  |  |                 earliest = d | 
					
						
							|  |  |  |             } else if (d < earliest) { | 
					
						
							|  |  |  |                 earliest = d | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (latest === undefined) { | 
					
						
							|  |  |  |                 latest = d | 
					
						
							|  |  |  |             } else if (d > latest) { | 
					
						
							|  |  |  |                 latest = d | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             allDates.add(d.toISOString()) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         while (earliest < latest) { | 
					
						
							|  |  |  |             earliest.setDate(earliest.getDate() + 1) | 
					
						
							|  |  |  |             allDates.add(earliest.toISOString()) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const days = Array.from(allDates) | 
					
						
							|  |  |  |         days.sort() | 
					
						
							|  |  |  |         return days | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  | export default class TagRenderingChart extends Combine { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |     public static readonly unkownColor = 'rgba(128, 128, 128, 0.2)' | 
					
						
							|  |  |  |     public static readonly unkownBorderColor = 'rgba(128, 128, 128, 0.2)' | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |     public static readonly otherColor = 'rgba(128, 128, 128, 0.2)' | 
					
						
							|  |  |  |     public static readonly otherBorderColor = 'rgba(128, 128, 255)' | 
					
						
							|  |  |  |     public static readonly notApplicableColor = 'rgba(128, 128, 128, 0.2)' | 
					
						
							|  |  |  |     public static readonly notApplicableBorderColor = 'rgba(255, 0, 0)' | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |     public static readonly backgroundColors = [ | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |         'rgba(255, 99, 132, 0.2)', | 
					
						
							|  |  |  |         'rgba(54, 162, 235, 0.2)', | 
					
						
							|  |  |  |         'rgba(255, 206, 86, 0.2)', | 
					
						
							|  |  |  |         'rgba(75, 192, 192, 0.2)', | 
					
						
							|  |  |  |         'rgba(153, 102, 255, 0.2)', | 
					
						
							|  |  |  |         'rgba(255, 159, 64, 0.2)' | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-20 12:46:33 +02:00
										 |  |  |     public static readonly borderColors = [ | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |         'rgba(255, 99, 132, 1)', | 
					
						
							|  |  |  |         'rgba(54, 162, 235, 1)', | 
					
						
							|  |  |  |         'rgba(255, 206, 86, 1)', | 
					
						
							|  |  |  |         'rgba(75, 192, 192, 1)', | 
					
						
							|  |  |  |         'rgba(153, 102, 255, 1)', | 
					
						
							|  |  |  |         'rgba(255, 159, 64, 1)' | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Creates a chart about this tagRendering for the given data | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |     constructor(features: { properties: Record<string, string> }[], tagRendering: TagRenderingConfig, options?: TagRenderingChartOptions & { | 
					
						
							|  |  |  |         chartclasses?: string, | 
					
						
							| 
									
										
										
										
											2022-07-20 15:04:51 +02:00
										 |  |  |         chartstyle?: string, | 
					
						
							|  |  |  |         includeTitle?: boolean, | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |         chartType?: "pie" | "bar" | "doughnut" | 
					
						
							|  |  |  |     }) { | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |         if (tagRendering.mappings?.length === 0 && tagRendering.freeform?.key === undefined) { | 
					
						
							| 
									
										
										
										
											2022-07-20 14:39:19 +02:00
										 |  |  |             super([]) | 
					
						
							|  |  |  |             this.SetClass("hidden") | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |         const {labels, data} = TagRenderingChart.extractDataAndLabels(tagRendering, features, options) | 
					
						
							|  |  |  |         if (labels === undefined || data === undefined) { | 
					
						
							| 
									
										
										
										
											2022-07-20 14:39:19 +02:00
										 |  |  |             super([]) | 
					
						
							|  |  |  |             this.SetClass("hidden") | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |             return | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |         const borderColor = [TagRenderingChart.unkownBorderColor, TagRenderingChart.otherBorderColor, TagRenderingChart.notApplicableBorderColor] | 
					
						
							|  |  |  |         const backgroundColor = [TagRenderingChart.unkownColor, TagRenderingChart.otherColor, TagRenderingChart.notApplicableColor] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |         while (borderColor.length < data.length) { | 
					
						
							|  |  |  |             borderColor.push(...TagRenderingChart.borderColors) | 
					
						
							|  |  |  |             backgroundColor.push(...TagRenderingChart.backgroundColors) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (let i = data.length; i >= 0; i--) { | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |             if (data[i]?.length === 0) { | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |                 labels.splice(i, 1) | 
					
						
							|  |  |  |                 data.splice(i, 1) | 
					
						
							|  |  |  |                 borderColor.splice(i, 1) | 
					
						
							|  |  |  |                 backgroundColor.splice(i, 1) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |         let barchartMode = tagRendering.multiAnswer; | 
					
						
							|  |  |  |         if (labels.length > 9) { | 
					
						
							| 
									
										
										
										
											2022-07-20 15:04:51 +02:00
										 |  |  |             barchartMode = true; | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-07-20 15:04:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |         const config = <ChartConfiguration>{ | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |             type: options.chartType ?? (barchartMode ? 'bar' : 'doughnut'), | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |             data: { | 
					
						
							|  |  |  |                 labels, | 
					
						
							|  |  |  |                 datasets: [{ | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |                     data: data.map(l => l.length), | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |                     backgroundColor, | 
					
						
							|  |  |  |                     borderColor, | 
					
						
							|  |  |  |                     borderWidth: 1, | 
					
						
							|  |  |  |                     label: undefined | 
					
						
							|  |  |  |                 }] | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             options: { | 
					
						
							|  |  |  |                 plugins: { | 
					
						
							|  |  |  |                     legend: { | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  |                         display: !barchartMode | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const chart = new ChartJs(config).SetClass(options?.chartclasses ?? "w-32 h-32"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (options.chartstyle !== undefined) { | 
					
						
							|  |  |  |             chart.SetStyle(options.chartstyle) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         super([ | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |             options?.includeTitle ? (tagRendering.question.Clone() ?? tagRendering.id) : undefined, | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |             chart]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.SetClass("block") | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     public static extractDataAndLabels<T extends { properties: Record<string, string> }>(tagRendering: TagRenderingConfig, features: T[], options?: TagRenderingChartOptions): { labels: string[], data: T[][] } { | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |         const mappings = tagRendering.mappings ?? [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         options = options ?? {} | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |         let unknownCount: T[] = []; | 
					
						
							|  |  |  |         const categoryCounts: T[][] = mappings.map(_ => []) | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |         const otherCounts: Record<string, T[]> = {} | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |         let notApplicable: T[] = []; | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |         for (const feature of features) { | 
					
						
							|  |  |  |             const props = feature.properties | 
					
						
							|  |  |  |             if (tagRendering.condition !== undefined && !tagRendering.condition.matchesProperties(props)) { | 
					
						
							|  |  |  |                 notApplicable.push(feature); | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!tagRendering.IsKnown(props)) { | 
					
						
							|  |  |  |                 unknownCount.push(feature); | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             let foundMatchingMapping = false; | 
					
						
							|  |  |  |             if (!tagRendering.multiAnswer) { | 
					
						
							|  |  |  |                 for (let i = 0; i < mappings.length; i++) { | 
					
						
							|  |  |  |                     const mapping = mappings[i]; | 
					
						
							|  |  |  |                     if (mapping.if.matchesProperties(props)) { | 
					
						
							|  |  |  |                         categoryCounts[i].push(feature) | 
					
						
							|  |  |  |                         foundMatchingMapping = true | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 for (let i = 0; i < mappings.length; i++) { | 
					
						
							|  |  |  |                     const mapping = mappings[i]; | 
					
						
							|  |  |  |                     if (TagUtils.MatchesMultiAnswer(mapping.if, props)) { | 
					
						
							|  |  |  |                         categoryCounts[i].push(feature) | 
					
						
							|  |  |  |                         foundMatchingMapping = true | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (!foundMatchingMapping) { | 
					
						
							|  |  |  |                 if (tagRendering.freeform?.key !== undefined && props[tagRendering.freeform.key] !== undefined) { | 
					
						
							|  |  |  |                     const otherValue = props[tagRendering.freeform.key] | 
					
						
							|  |  |  |                     otherCounts[otherValue] = (otherCounts[otherValue] ?? []) | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |                     otherCounts[otherValue].push(feature) | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |                 } else { | 
					
						
							|  |  |  |                     unknownCount.push(feature) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (unknownCount.length + notApplicable.length === features.length) { | 
					
						
							|  |  |  |             console.log("Returning no label nor data: all features are unkown or notApplicable") | 
					
						
							|  |  |  |             return {labels: undefined, data: undefined} | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |         let otherGrouped: T[] = []; | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  |         const otherLabels: string[] = [] | 
					
						
							|  |  |  |         const otherData: T[][] = [] | 
					
						
							|  |  |  |         const sortedOtherCounts: [string, T[]][] = [] | 
					
						
							|  |  |  |         for (const v in otherCounts) { | 
					
						
							|  |  |  |             sortedOtherCounts.push([v, otherCounts[v]]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (options?.sort) { | 
					
						
							|  |  |  |             sortedOtherCounts.sort((a, b) => b[1].length - a[1].length) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         for (const [v, count] of sortedOtherCounts) { | 
					
						
							|  |  |  |             if (count.length >= (options.groupToOtherCutoff ?? 3)) { | 
					
						
							|  |  |  |                 otherLabels.push(v) | 
					
						
							|  |  |  |                 otherData.push(otherCounts[v]) | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 otherGrouped.push(...count); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const labels = ["Unknown", "Other", "Not applicable", ...mappings?.map(m => m.then.txt) ?? [], ...otherLabels] | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  |         const data: T[][] = [unknownCount, otherGrouped, notApplicable, ...categoryCounts, ...otherData] | 
					
						
							| 
									
										
										
										
											2022-08-18 23:37:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return {labels, data} | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-22 13:34:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  | } |