| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- 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;
- }
- }
|