import * as hsv2rgb from 'hsv2rgb';
import {Feature} from 'ol';
import {Fill, Stroke, Style} from 'ol/style';
import {GeoJSON} from 'ol/format';
import {Injectable} from '@angular/core';
import {Vector as VectorLayer} from 'ol/layer';
import {Vector as VectorSource} from 'ol/source';
import {HsConfig} from 'hslayers-ng/config.service';
import {HsLayoutService} from 'hslayers-ng/components/layout/layout.service';
import {HsMapService} from 'hslayers-ng/components/map/map.service';
import {HsPanelContainerService} from 'hslayers-ng/components/layout/panels/panel-container.service';
import {HsSidebarService} from 'hslayers-ng/components/sidebar/sidebar.service';
import {AdjusterComponent} from './adjuster/adjuster.component';
import {AdjusterEventService} from './adjuster/adjuster-event.service';
import {AdjusterService} from './adjuster/adjuster.service';
import {nuts} from './nuts';
@Injectable({providedIn: 'root'})
export class AppService {
// https://colorbrewer2.org/?type=qualitative&scheme=Paired&n=12
colorPalette = [
'#a6cee3',
'#1f78b4',
'#b2df8a',
'#33a02c',
'#fb9a99',
'#e31a1c',
'#fdbf6f',
'#ff7f00',
'#cab2d6',
'#6a3d9a',
'#ffff99',
'#b15928',
];
nuts2style = new Style({
stroke: new Stroke({
color: '#000000',
width: 0.5,
}),
});
nuts2Layer = new VectorLayer({
source: nuts.nuts2Source,
editor: {editable: false},
visible: false,
style: this.nuts2style,
title: 'NUTS2 regions',
});
nuts3Layer = new VectorLayer({
source: nuts.nuts3Source,
editor: {editable: false},
visible: true,
style: this.generateStyle(this.adjusterService.method),
title: 'NUTS3 regions',
});
pilotsStyle = new Style({
stroke: new Stroke({
color: '#1d941d',
width: 1.5,
}),
fill: new Fill({
color: 'rgba(29, 148, 29, 0.2)',
}),
});
pilotRegions = new VectorLayer({
source: new VectorSource({
format: new GeoJSON(),
url: require('./data/pilot_regions.geojson').default,
}),
editor: {editable: false},
visible: true,
style: this.pilotsStyle,
title: 'Polirural Pilot Regions',
});
serviceUrl: string;
constructor(
private adjusterService: AdjusterService,
private adjusterEventService: AdjusterEventService,
private hsConfig: HsConfig,
private hsLayoutService: HsLayoutService,
private hsMapService: HsMapService,
private hsSidebarService: HsSidebarService,
private hsPanelContainerService: HsPanelContainerService
) {
this.serviceUrl = this.adjusterService.serviceBaseUrl + 'georeport/';
this.nuts3Layer.set('popUp', {
attributes: [
{attribute: 'CNTR_CODE', label: 'Country'},
{attribute: 'NUTS_NAME', label: 'Name'},
{attribute: this.adjusterService.method /*, label: 'Cluster ID'*/},
{
attribute: 'NUTS_ID',
label: 'Detailed report',
displayFunction: (x) => {
return `in a new page.`;
},
},
],
});
this.pilotRegions.set('popUp', {
attributes: [
{attribute: 'NUTS_NAME', label: 'Region name'},
//TODO: Uncomment when implemented in the rural-attractiveness-service
/*{
attribute: 'NUTS_ID',
label: 'Pilot region details',
displayFunction: (x) => {
return `in a new page.`;
},
},*/
],
});
this.adjusterEventService.clustersLoaded.subscribe(() => {
this.colorPalette = this.generateRandomColorPalette(
adjusterService.clusters.length
);
});
this.adjusterEventService.methodChanged.subscribe((method) => {
this.nuts3Layer.get('popUp').attributes[2].attribute = method;
this.nuts3Layer.setStyle(this.generateStyle(this.adjusterService.method));
});
/* The order of pushes matter! */
this.hsConfig.default_layers.push(this.nuts3Layer);
this.hsConfig.default_layers.push(this.nuts2Layer);
this.hsConfig.default_layers.push(this.pilotRegions);
/*this.hsMapService
.loaded()
.then((map) => this.hsMapService.repopulateLayers([]));*/
this.init();
}
init(): void {
this.hsSidebarService.buttons.push({
panel: 'adjuster',
module: 'pra.adjuster',
order: 0,
title: 'Adjust factors',
description: 'Adjust factors for computation',
icon: 'icon-analytics-piechart',
});
this.hsPanelContainerService.create(AdjusterComponent, {});
this.hsLayoutService.setDefaultPanel('adjuster');
//this.hsLayoutService.sidebarRight = false;
}
/**
* https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
* @private
* @description Only generates random colors if the current palette does not provide enough colors for all the clusters
* @param {number} colorCount Number of colors to randomly generate
* @returns {Array | string>} Array of RGB colors
*/
private generateRandomColorPalette(colorCount: number) {
const palette = this.colorPalette;
const goldenRatioConjugate = 0.618033988749895;
let i = palette.length;
while (i < colorCount) {
let h = Math.random();
h += goldenRatioConjugate;
h %= 1;
h *= 360;
palette.push(hsv2rgb(h, 0.5, 0.95));
i++;
}
return palette;
//return `rgba(${r}, ${g}, ${b}, 0.7)`;
}
/**
* @description Function factory for generating style functions based on different clustering methods
* @param {string} method currently selected method
* @returns {function} style function
*/
private generateStyle(method: string) {
return (feature: Feature): Style => {
if (isNaN(feature.get(method))) {
return new Style({
fill: new Fill({
color: '#FFF',
}),
stroke: new Stroke({
color: '#3399CC',
width: 0.25,
}),
});
} else {
return new Style({
fill: new Fill({
color: this.colorPalette[feature.get(method) - 1],
}),
stroke: new Stroke({
color: '#FFF',
width: 0.25,
}),
});
}
};
}
}