import {Component} from '@angular/core'; import {interpolate, quantize, select} from 'd3'; import {SdmDihService} from '../sdm-dih.service'; @Component({ selector: 'year-graph', templateUrl: './year-graph.component.html', styleUrls: ['./year-graph.component.scss'], }) export class YearGraphComponent { selectedYear = ''; constructor(public sdmDihService: SdmDihService) { this.sdmDihService.dataLoads.subscribe(() => { this.selectedYear = this.sdmDihService.firstYear; this.redrawGraphs(); this.drawLegend(); }); } animateGraphs() { const MILLISECONDS_TO_ANIMATE = 100 as const; let i = 1; for (const year of this.sdmDihService.years) { setTimeout(() => { this.selectedYear = year; this.redrawGraphs(); }, MILLISECONDS_TO_ANIMATE * i); i++; } } drawGraph(region: string) { const year = this.selectedYear.toString().includes('.') ? this.selectedYear : this.selectedYear + '.0'; const regionData = this.sdmDihService.sdmData[year].find( (row) => row['MODEL'] === region ); const width = 100 / this.sdmDihService.regions.length; const height = 100 / this.sdmDihService.regions.length; // append the svg object to the div called 'year-graph-place' const svg = select('#year-graph-place') .append('svg') .attr('width', `${width}%`) .attr('height', `${height}%`) .append('svg') .attr('x', '50%') .attr('y', '50%') .attr('overflow', 'visible'); // arrow symbol for later re-use const arrow = svg.append('symbol').attr('id', 'arrow'); // horizontal line arrow .append('line') .attr('x1', 0) .attr('y1', 30) .attr('x2', 60) .attr('y2', 30) .attr('stroke', 'black') .style('stroke-width', 4); // upper line arrow .append('line') .attr('x1', 40) .attr('y1', 10) .attr('x2', 60) .attr('y2', 30) .attr('stroke', 'black') .style('stroke-width', 4); // bottom line arrow .append('line') .attr('x1', 40) .attr('y1', 50) .attr('x2', 60) .attr('y2', 30) .attr('stroke', 'black') .style('stroke-width', 4); const svgContent = svg.append('g').data([regionData]); //.attr('transform', 'translate(' + width / 2 + '% ,' + height / 2 + '% )'); svgContent .append('circle') .attr('cx', 0) .attr('cy', 0) .attr('r', 50) .attr('stroke', 'black') .attr('fill', (d) => { return this.sdmDihService.perc2color(d['aggregated']); }); svgContent .append('text') .attr('x', 0) .attr('y', -60) .attr('dy', '.35em') .text((d) => d['MODEL']) .style('text-anchor', 'middle'); svgContent .append('text') .attr('x', 0) .attr('y', 60) .attr('dy', '.35em') .text((d) => `${(Number.parseFloat(d['aggregated']) * 100).toFixed(2)} %`) .style('text-anchor', 'middle'); svgContent .append('text') .attr('x', 0) .attr('y', 60) .attr('dy', '.35em') .text((d) => `${(Number.parseFloat(d['aggregated']) * 100).toFixed(2)} %`) .style('text-anchor', 'middle'); svgContent .append('use') .attr('xlink:href', '#arrow') .attr('x', -30) .attr('y', -30) .attr( 'transform', // rotation is defined clockwise, hence -45 deg will turn the arrow up (d) => `rotate(${-45 * this.getRegionProgress(d)}, 0, 0)` ); } drawLegend() { const width = 200; const height = 20; const g = select('#year-graph-legend-place') .append('svg') .attr('width', width) .attr('height', height) .attr('viewBox', [0, 0, width, height]) .style('overflow', 'visible') .style('display', 'block') .append('g'); for (let i = 0; i < 10; i++) { g.append('rect') .attr('x', i * 20) .attr('y', 0) .attr('width', width / 10) .attr('height', height / 2) .attr('fill', this.sdmDihService.perc2color(i / 10)); } g.append('text') .attr('x', 0 - 10) .attr('y', 20) .attr('dy', '.5em') .text('0 %'); g.append('text') .attr('x', 200 - 10) .attr('y', 20) .attr('dy', '.5em') .text('100 %'); } redrawGraphs() { const width = 200; const height = 200; select('#year-graph-place').selectAll('svg')?.remove(); for (const region of this.sdmDihService.regions) { this.drawGraph(region); } } getRegionProgress(regionData): -1 | 0 | 1 { //TODO: parametrize the PARAM_TO_COMPARE //TODO: use i-2, i-1 comparison based on 2 previous steps const PARAM_TO_COMPARE = 'aggregated'; const region = regionData['MODEL']; const year = regionData['TIME_STEP']; const thisYearValue = +Number.parseFloat( regionData[PARAM_TO_COMPARE] ).toFixed(3); let pastYear = Number.parseFloat(year) - 0.25 + ''; pastYear = pastYear.includes('.') ? pastYear : pastYear + '.0'; const pastYearData = this.sdmDihService.sdmData[pastYear]; if (!pastYearData) { // We are in the first time step, so there is nothing to compare return 0; } let pastYearValue = pastYearData.find( (regionPastYear) => regionPastYear['MODEL'] === region )?.[PARAM_TO_COMPARE]; pastYearValue = +Number.parseFloat(pastYearValue).toFixed(3); if (pastYearValue < thisYearValue) { return 1; } if (pastYearValue > thisYearValue) { return -1; } return 0; } }