| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  | import ChartJs from "../Base/ChartJs"; | 
					
						
							|  |  |  | import {OsmFeature} from "../../Models/OsmFeature"; | 
					
						
							|  |  |  | 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-07-20 12:04:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | export default class TagRenderingChart extends Combine { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static readonly unkownColor = 'rgba(128, 128, 128, 0.2)' | 
					
						
							|  |  |  |     private static readonly unkownBorderColor = 'rgba(128, 128, 128, 0.2)' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static readonly otherColor = 'rgba(128, 128, 128, 0.2)' | 
					
						
							|  |  |  |     private static readonly otherBorderColor = 'rgba(128, 128, 255)' | 
					
						
							|  |  |  |     private static readonly notApplicableColor = 'rgba(128, 128, 128, 0.2)' | 
					
						
							|  |  |  |     private static readonly notApplicableBorderColor = 'rgba(255, 0, 0)' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static readonly backgroundColors = [ | 
					
						
							|  |  |  |         '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)' | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static readonly borderColors = [ | 
					
						
							|  |  |  |         '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 | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     constructor(features: OsmFeature[], tagRendering: TagRenderingConfig, options?: { | 
					
						
							|  |  |  |         chartclasses?: string, | 
					
						
							| 
									
										
										
										
											2022-07-20 15:04:51 +02:00
										 |  |  |         chartstyle?: string, | 
					
						
							|  |  |  |         includeTitle?: boolean, | 
					
						
							|  |  |  |         groupToOtherCutoff?: 3 | number | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |     }) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const mappings = tagRendering.mappings ?? [] | 
					
						
							|  |  |  |         if (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; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         let unknownCount = 0; | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  |         const categoryCounts = mappings.map(_ => 0) | 
					
						
							|  |  |  |         const otherCounts: Record<string, number> = {} | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |         let notApplicable = 0; | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  |         let barchartMode = tagRendering.multiAnswer; | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |         for (const feature of features) { | 
					
						
							|  |  |  |             const props = feature.properties | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  |             if (tagRendering.condition !== undefined && !tagRendering.condition.matchesProperties(props)) { | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |                 notApplicable++; | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |             if (!tagRendering.IsKnown(props)) { | 
					
						
							|  |  |  |                 unknownCount++; | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             let foundMatchingMapping = false; | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  |             if (!tagRendering.multiAnswer) { | 
					
						
							|  |  |  |                 for (let i = 0; i < mappings.length; i++) { | 
					
						
							|  |  |  |                     const mapping = mappings[i]; | 
					
						
							|  |  |  |                     if (mapping.if.matchesProperties(props)) { | 
					
						
							|  |  |  |                         categoryCounts[i]++ | 
					
						
							|  |  |  |                         foundMatchingMapping = true | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |                         break; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 for (let i = 0; i < mappings.length; i++) { | 
					
						
							|  |  |  |                     const mapping = mappings[i]; | 
					
						
							|  |  |  |                     if (TagUtils.MatchesMultiAnswer( mapping.if, props)) { | 
					
						
							|  |  |  |                         categoryCounts[i]++ | 
					
						
							| 
									
										
										
										
											2022-07-20 15:04:51 +02:00
										 |  |  |                         foundMatchingMapping = true | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  |             if (!foundMatchingMapping) { | 
					
						
							|  |  |  |                 if (tagRendering.freeform?.key !== undefined && props[tagRendering.freeform.key] !== undefined) { | 
					
						
							|  |  |  |                     const otherValue = props[tagRendering.freeform.key] | 
					
						
							|  |  |  |                     otherCounts[otherValue] = (otherCounts[otherValue] ?? 0) + 1 | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     unknownCount++ | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (unknownCount + notApplicable === features.length) { | 
					
						
							| 
									
										
										
										
											2022-07-20 14:39:19 +02:00
										 |  |  |             super([]) | 
					
						
							|  |  |  |             this.SetClass("hidden") | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  |         let otherGrouped = 0; | 
					
						
							|  |  |  |         const otherLabels: string[] = [] | 
					
						
							|  |  |  |         const otherData : number[] = [] | 
					
						
							|  |  |  |         for (const v in otherCounts) { | 
					
						
							|  |  |  |             const count = otherCounts[v] | 
					
						
							| 
									
										
										
										
											2022-07-20 15:04:51 +02:00
										 |  |  |             if(count >= (options.groupToOtherCutoff ?? 3)){ | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  |                 otherLabels.push(v) | 
					
						
							|  |  |  |                 otherData.push(otherCounts[v]) | 
					
						
							|  |  |  |             }else{ | 
					
						
							|  |  |  |                 otherGrouped++; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-07-20 15:04:51 +02:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											2022-07-20 14:06:39 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const labels = ["Unknown", "Other", "Not applicable", ...mappings?.map(m => m.then.txt) ?? [], ...otherLabels] | 
					
						
							|  |  |  |         const data = [unknownCount, otherGrouped, notApplicable, ...categoryCounts, ... otherData] | 
					
						
							| 
									
										
										
										
											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--) { | 
					
						
							|  |  |  |             if (data[i] === 0) { | 
					
						
							|  |  |  |                 labels.splice(i, 1) | 
					
						
							|  |  |  |                 data.splice(i, 1) | 
					
						
							|  |  |  |                 borderColor.splice(i, 1) | 
					
						
							|  |  |  |                 backgroundColor.splice(i, 1) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 15:04:51 +02:00
										 |  |  |         if(labels.length > 9){ | 
					
						
							|  |  |  |             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-07-20 14:06:39 +02:00
										 |  |  |             type: barchartMode ? 'bar' : 'doughnut', | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |             data: { | 
					
						
							|  |  |  |                 labels, | 
					
						
							|  |  |  |                 datasets: [{ | 
					
						
							|  |  |  |                     data, | 
					
						
							|  |  |  |                     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-07-20 15:04:51 +02:00
										 |  |  |            options?.includeTitle ?  (tagRendering.question.Clone() ?? tagRendering.id) : undefined, | 
					
						
							| 
									
										
										
										
											2022-07-20 12:04:14 +02:00
										 |  |  |             chart]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.SetClass("block") | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |