diff --git a/src/app/pages/simulation-wizard/results-map/map-colors-local.ts b/src/app/pages/simulation-wizard/results-map/map-colors-local.ts index 5c9d98d4c9272c386d7108b29d9ce0adba979f47..fcbf11b5997f3972684ef08ed9d9f04a6d28d8c3 100644 --- a/src/app/pages/simulation-wizard/results-map/map-colors-local.ts +++ b/src/app/pages/simulation-wizard/results-map/map-colors-local.ts @@ -6,9 +6,51 @@ const color_2 = "#fed98b"; const color_3 = "#c2e3ee"; const color_4 = "#6da5cc"; const color_5 = "#35b499"; +// const color_5 = "darkseagreen"; +// const color_4 = "cornflowerblue"; +// const color_3 = "lightblue"; +// const color_2 = "navajowhite"; +// const color_1 = "orange"; +// const color_0 = "red"; const color_capacity_equal_9999 = "#ffffff00"; const color_value_undefined = "#9efcff33"; +export function getNewColor( + bioSection, + properties: any, + pro: any, + isCapacityEqual9999: boolean +): string { + if (isCapacityEqual9999 == true) { + return color_capacity_equal_9999; + } + let value = undefined; + + if (pro == "pedestrianTravelTime") { + value = properties; + } else { + for (let key in properties) { + if (key == pro) { + value = properties[key]; + } + } + } + + if (value == undefined) return color_value_undefined; + + return value > bioSection.get("legend_4").value + ? color_0 + : value > bioSection.get("legend_3").value + ? color_1 + : value > bioSection.get("legend_2").value + ? color_2 + : value > bioSection.get("legend_1").value + ? color_3 + : value > bioSection.get("legend_0").value + ? color_4 + : color_5; +} + export function getColor( properties: any, pro: any, @@ -86,18 +128,17 @@ export function getColorHighToLow( } export function getColorForLegend( - d: number, - current_brink_values: object + id: number, ): string { - return current_brink_values[d] > current_brink_values[4] + return id == 5 ? color_0 - : current_brink_values[d] > current_brink_values[3] + : id == 4 ? color_1 - : current_brink_values[d] > current_brink_values[2] + : id == 3 ? color_2 - : current_brink_values[d] > current_brink_values[1] + : id == 2 ? color_3 - : current_brink_values[d] > current_brink_values[0] + : id == 1 ? color_4 : color_5; } diff --git a/src/app/pages/simulation-wizard/results-map/results-map.component.html b/src/app/pages/simulation-wizard/results-map/results-map.component.html index 49c0484015a56142d16d776be3e60c76b9dacea5..b5af729b62edf9a82fb2ba46569b6801fa0bae67 100644 --- a/src/app/pages/simulation-wizard/results-map/results-map.component.html +++ b/src/app/pages/simulation-wizard/results-map/results-map.component.html @@ -64,5 +64,83 @@ (change)="grayscaleChange()" /> </div> + <div id="inputsLegendContainer"> + <form [formGroup]="newLegendValues" (ngSubmit)="onNewLegendSubmit()"> + <section> + <div> + <div> + <label style="background: #35b499" for="">1st color, up to</label> + <input + nbInput + size="tiny" + type="number" + min="0" + max="1000000" + style="background-color: #35b499" + formControlName="legend_0" + /> + </div> + <div> + <label style="background: #6da5cc" for="">2nd color, up to</label> + <input + nbInput + size="tiny" + type="number" + min="0" + max="1000000" + style="background-color: #6da5cc" + formControlName="legend_1" + /> + </div> + <div> + <label style="background: #c2e3ee" for="">3rd color, up to</label> + <input + nbInput + size="tiny" + type="number" + min="0" + max="1000000" + style="background-color: #c2e3ee" + formControlName="legend_2" + /> + </div> + <div> + <label style="background: #fed98b" for="">4th color, up to</label> + <input + nbInput + size="tiny" + type="number" + min="0" + max="1000000" + style="background-color: #fed98b" + formControlName="legend_3" + /> + </div> + <div> + <label style="background: #f57d4a" for="">5th color, up to</label> + <input + nbInput + size="tiny" + type="number" + min="0" + max="1000000" + style="background-color: #f57d4a" + formControlName="legend_4" + /> + </div> + <div> + <label style="background: #a50026" for="" + >6th color, up to unlimited</label + > + </div> + </div> + <div> + <button nbButton status="primary" type="submit"> + Confirm new legend + </button> + </div> + </section> + </form> + </div> </nb-card-body> </nb-card> diff --git a/src/app/pages/simulation-wizard/results-map/results-map.component.scss b/src/app/pages/simulation-wizard/results-map/results-map.component.scss index e4d50741c5455ed20a4558101ebb779db4598d3d..4079152472cc8d9f79cb0fa190ce1b59b91d7085 100644 --- a/src/app/pages/simulation-wizard/results-map/results-map.component.scss +++ b/src/app/pages/simulation-wizard/results-map/results-map.component.scss @@ -28,7 +28,7 @@ padding: 4px 3px 0 3px; } #loadGeojsonButtonsContainer { - z-index: 997; + z-index: 1003; position: absolute; top: 5px; left: 57px; @@ -42,6 +42,30 @@ text-transform: capitalize; } } + #inputsLegendContainer { + padding: 10px; + section { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + margin-bottom: 10px; + } + div label { + display: inline-block; + width: 140px; + border-radius: 0.25rem; + text-align: right; + font-weight: bold; + background: #fff; + padding: 2px 5px; + } + input { + margin: 2px 5px; + height: 1rem; + width: 10rem; + } + } } nb-radio { display: inline; diff --git a/src/app/pages/simulation-wizard/results-map/results-map.component.ts b/src/app/pages/simulation-wizard/results-map/results-map.component.ts index a871f2090687216278c1a4833f283a2c4fb575d4..e7823cbbc9d8b922a8f224b7d9cb81510a66aa8b 100644 --- a/src/app/pages/simulation-wizard/results-map/results-map.component.ts +++ b/src/app/pages/simulation-wizard/results-map/results-map.component.ts @@ -6,6 +6,7 @@ import { legendInverted, ratiosBetweenGrades } from "./results-map-settings"; import { NbToastrService, NbDialogService } from "@nebular/theme"; import { Simulation } from "../utils/data/simulation"; import { NetworkService } from "../utils/services/network.service"; +import { FormControl, FormGroup } from "@angular/forms"; @Component({ selector: "ngx-results-map", @@ -36,6 +37,14 @@ export class ResultsMapComponent implements OnChanges { @Input() selectedSimulation: Simulation; selectedGeojson: string = ""; extractingKeysLoopLimit: number = 3498; + newLegendValues = new FormGroup({ + legend_0: new FormControl(undefined), + legend_1: new FormControl(undefined), + legend_2: new FormControl(undefined), + legend_3: new FormControl(undefined), + legend_4: new FormControl(undefined), + legend_5: new FormControl(undefined), + }); constructor( private simulationService: SimulationService, @@ -52,26 +61,34 @@ export class ResultsMapComponent implements OnChanges { this.setMapPositionAndZoom(res); }); }, 50); + setTimeout(() => { + console.log( + "%cTemporary", + "background: peru; font-weight: bold; color: black; font-family: serif; padding: 0 10px;" + ); + const celkomplet: HTMLElement = document.querySelectorAll( + ".buttons" + )[0] as HTMLElement; + celkomplet.style.display = "none"; + }, 825); + setTimeout(() => { + const celkomplet1: HTMLElement = document.querySelectorAll( + ".appearance-filled.size-medium.shape-rectangle.status-primary.ng-star-inserted.nb-transition" + )[1] as HTMLElement; + celkomplet1.click(); + }, 1000); + setTimeout(() => { + const celkomplet2: HTMLElement = document.querySelectorAll( + "#loadGeojsonButtonsContainer button" + )[3] as HTMLElement; + celkomplet2.click(); + }, 1050); // setTimeout(() => { - // console.log( - // "%cTemporary", - // "background: crimson; font-weight: bold; color: black; font-family: serif; padding: 0 10px;" - // ); - // const celkomplet: HTMLElement = document.querySelectorAll( - // ".appearance-filled.size-medium.shape-rectangle.status-primary.ng-star-inserted.nb-transition" - // )[1] as HTMLElement; - // celkomplet.click(); - // }, 995); - // setTimeout(() => { - // console.log( - // "%cTemporary", - // "background: peru; font-weight: bold; color: black; font-family: serif; padding: 0 10px;" - // ); - // const celkomplet: HTMLElement = document.querySelectorAll( - // ".buttons" - // )[0] as HTMLElement; - // celkomplet.style.display = "none"; - // }, 1000); + // const celkomplet3: HTMLElement = document.querySelectorAll( + // ".leaflet-control-layers-selector" + // )[2] as HTMLElement; + // celkomplet3.click(); + // }, 2228); } onLoadClick(selectedKpi: string) { @@ -127,10 +144,10 @@ export class ResultsMapComponent implements OnChanges { if (res["message"] == "Calculating...") { this.toastrService.show( - "Server says: Calculating the KPI visualization. GEOJSON loading will not be completed. When it will be ready, you will need to refresh the page or click again on this button.", + "Server says: Calculating the KPI visualization. GEOJSON loading will not be completed.", "Geojson not ready", { - status: "control", + status: "danger", duration: 10000, } ); @@ -180,19 +197,16 @@ export class ResultsMapComponent implements OnChanges { if ( propertyGeojsons[i].myKey == "link_id" || propertyGeojsons[i].myKey == "modes" || - propertyGeojsons[i].myKey == "internal_travel_by_mode" || - propertyGeojsons[i].myKey == "pt_vehicles" - ) { - console.log("Ignoring key ", propertyGeojsons[i].myKey); + propertyGeojsons[i].myKey == "internal_travel_by_mode" + ) continue; - } obj[`${keys[i]}`] = propertyGeojsons[i]; } this.radioButtonLayersControl = new L.Control.Layers(obj, null, { collapsed: false, }); this.map.addControl(this.radioButtonLayersControl); - this.addListenerToRadioButtonLayersControl(); + this.addListenerToRadioButtonLayersControlAndSetLegend(); this.geojsonLoading = false; } @@ -227,52 +241,74 @@ export class ResultsMapComponent implements OnChanges { } var div = L.DomUtil.create("div"); - const grades = [ - 0, - this.limitMyDigits( - this.maxKeyValues["maxValue_" + legendType] / ratiosBetweenGrades[0] - ), - this.limitMyDigits( - this.maxKeyValues["maxValue_" + legendType] / ratiosBetweenGrades[1] - ), - this.limitMyDigits( - this.maxKeyValues["maxValue_" + legendType] / ratiosBetweenGrades[2] - ), - this.limitMyDigits( - this.maxKeyValues["maxValue_" + legendType] / ratiosBetweenGrades[3] - ), - this.limitMyDigits( - this.maxKeyValues["maxValue_" + legendType] / ratiosBetweenGrades[4] - ), - ]; + let grades; + + if ( + this.newLegendValues.get("legend_0").touched || + this.newLegendValues.get("legend_1").touched || + this.newLegendValues.get("legend_2").touched || + this.newLegendValues.get("legend_3").touched || + this.newLegendValues.get("legend_4").touched || + this.newLegendValues.get("legend_5").touched + ) { + grades = [ + 0, + this.newLegendValues.get("legend_0").value, + this.newLegendValues.get("legend_1").value, + this.newLegendValues.get("legend_2").value, + this.newLegendValues.get("legend_3").value, + this.newLegendValues.get("legend_4").value, + ]; + } else { + grades = [ + 0, + this.limitMyDigits( + this.maxKeyValues["maxValue_" + legendType] / ratiosBetweenGrades[0] + ), + this.limitMyDigits( + this.maxKeyValues["maxValue_" + legendType] / ratiosBetweenGrades[1] + ), + this.limitMyDigits( + this.maxKeyValues["maxValue_" + legendType] / ratiosBetweenGrades[2] + ), + this.limitMyDigits( + this.maxKeyValues["maxValue_" + legendType] / ratiosBetweenGrades[3] + ), + this.limitMyDigits( + this.maxKeyValues["maxValue_" + legendType] / ratiosBetweenGrades[4] + ), + ]; + } if (direction == "lowToHigh") { div.innerHTML += "<p style='background:white; display: inline; font-size:17px'> <span style='color:" + - MapColors.getColorForLegend(0, grades) + + MapColors.getColorForLegend(0) + "'>■</span> <" + grades[1] + "</p>"; for (let i = 1; i < 6; i++) { div.innerHTML += "<p style='background:white; display: inline; font-size:17px'> <span style='color:" + - MapColors.getColorForLegend(i, grades) + + MapColors.getColorForLegend(i) + "'>■</span> " + grades[i] + (grades[i + 1] ? "–" + grades[i + 1] + "</p>" : "+</p>"); + this.newLegendValues.get(`legend_${i - 1}`).setValue(`${grades[i]}`); } } else { for (let i = 5; i > 0; i--) { div.innerHTML += "<p style='background:white; display: inline; font-size:17px'> <span style='color:" + - MapColors.getColorForLegend(5 - i, grades) + + MapColors.getColorForLegend(5 - i) + "'>■</span> " + grades[i] + (grades[i + 1] ? "–" + grades[i + 1] + "</p>" : "+</p>"); + this.newLegendValues.get(`legend_${i - 1}`).setValue(`${grades[i]}`); } div.innerHTML += "<p style='background:white; display: inline; font-size:17px'> <span style='color:" + - MapColors.getColorForLegend(5, grades) + + MapColors.getColorForLegend(5) + "'>■</span> <" + grades[1] + "</p>"; @@ -508,7 +544,7 @@ export class ResultsMapComponent implements OnChanges { return res; } - public addListenerToRadioButtonLayersControl() { + public addListenerToRadioButtonLayersControlAndSetLegend() { this.map.on("baselayerchange", (e) => { this.setLegend(e["name"]); this.checkedRadioButton = e["name"]; @@ -622,16 +658,105 @@ export class ResultsMapComponent implements OnChanges { } setLoadGeojsons() { - this.networkService.getKpiVisInfo().subscribe((res) => { - this.loadGeojsons = []; - res.forEach((but) => { - this.loadGeojsons.push({ - response: undefined, - buttonValue: but["buttonValue"], - buttonLabel: but["buttonLabel"], + if (this.selectedSimulation != undefined) { + if (this.selectedSimulation["city"]["cityId"] == "amsterdam") { + this.loadGeojsons = [ + { + response: undefined, + buttonValue: "bikeability", + buttonLabel: "bikeability", + }, + { + response: undefined, + buttonValue: "bikeIntensity", + buttonLabel: "bike Intensity", + }, + { + response: undefined, + buttonValue: "bikeSafety", + buttonLabel: "bike Safety", + }, + { + response: undefined, + buttonValue: "pollution", + buttonLabel: "pollution", + }, + ]; + } else if (this.selectedSimulation["city"]["cityId"] == "bilbao") { + this.loadGeojsons = [ + { + response: undefined, + buttonValue: "bikeability", + buttonLabel: "bikeability", + }, + { + response: undefined, + buttonValue: "bikeIntensity", + buttonLabel: "bike Intensity", + }, + { + response: undefined, + buttonValue: "bikeSafety", + buttonLabel: "bike Safety", + }, + { + response: undefined, + buttonValue: "pollution", + buttonLabel: "pollution", + }, + ]; + } else if (this.selectedSimulation["city"]["cityId"] == "helsinki") { + this.loadGeojsons = [ + { + response: undefined, + buttonValue: "congestionsAndBottlenecks", + buttonLabel: "congestions And Bottlenecks", + }, + { + response: undefined, + buttonValue: "harbourAreaTrafficFlow", + buttonLabel: "harbour Area Traffic Flow", + }, + { + response: undefined, + buttonValue: "accousticPollution", + buttonLabel: "accoustic Pollution", + }, + { + response: undefined, + buttonValue: "pollution", + buttonLabel: "pollution", + }, + ]; + } else if (this.selectedSimulation["city"]["cityId"] == "messina") { + this.loadGeojsons = [ + { + response: undefined, + buttonValue: "bikeability", + buttonLabel: "bikeability", + }, + { + response: undefined, + buttonValue: "bikeIntensity", + buttonLabel: "bike Intensity", + }, + { + response: undefined, + buttonValue: "bikeSafety", + buttonLabel: "bike Safety", + }, + { + response: undefined, + buttonValue: "pollution", + buttonLabel: "pollution", + }, + ]; + } else { + this.toastrService.show("Unexpected value for city name.", "Error", { + status: "danger", }); - }); - }); + } + } } openOverviewOfIndicators(dialog: TemplateRef<any>) { @@ -671,4 +796,70 @@ export class ResultsMapComponent implements OnChanges { res["zoom"] ); } + + onNewLegendSubmit() { + console.log( + "%c for some reason this DESELECTS radio button and also layers", + "background: darkgoldenrod; color: black; font-weight: bold;" + ); + + if (this.radioButtonLayersControl) + this.radioButtonLayersControl.remove(this.map); + this.resetLayersAndButton(); + + const keys = this.extractKeys(this.loadGeojsons[3]["response"]); + const jsonFile = this.loadGeojsons[3]["response"]; + let propertyGeojsons = []; + + for (let f = 0; f < keys.length; f++) { + let tmp: Object = {}; + + if ( + this.maxKeyValues["maxValue_" + keys[f]] == undefined || + this.maxKeyValues["maxValue_" + keys[f]] == 0 + ) { + tmp = L.geoJSON(<any>{ + type: "FeatureCollection", + features: [], + }); + } else { + tmp = L.geoJSON(<any>jsonFile, { + style: (feature) => ({ + weight: this.geoJsonStyleWeight, + color: MapColors.getNewColor( + this.newLegendValues, + feature["properties"], + keys[f], + parseInt(feature["properties"]["capacity"]) == 9999 ? true : false + ), + opacity: this.geoJsonStyleOpacity, + }), + onEachFeature: (feature, layer) => + layer.on({ + mouseover: (e) => this.highlightFeature(e, feature.properties), + mouseout: (e) => this.resetFeature(e, feature.properties), + }), + }); + propertyGeojsons.push(tmp); + } + tmp["myKey"] = keys[f]; + } + + let obj = {}; + + for (let i = 0; i < propertyGeojsons.length; i++) { + if ( + propertyGeojsons[i].myKey == "link_id" || + propertyGeojsons[i].myKey == "modes" || + propertyGeojsons[i].myKey == "internal_travel_by_mode" + ) + continue; + obj[`${keys[i]}`] = propertyGeojsons[i]; + } + this.radioButtonLayersControl = new L.Control.Layers(obj, null, { + collapsed: false, + }); + this.map.addControl(this.radioButtonLayersControl); + this.addListenerToRadioButtonLayersControlAndSetLegend(); + } }