app.service.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import * as hsv2rgb from 'hsv2rgb';
  2. import {Feature} from 'ol';
  3. import {Fill, Stroke, Style} from 'ol/style';
  4. import {GeoJSON} from 'ol/format';
  5. import {Injectable} from '@angular/core';
  6. import {Vector as VectorLayer} from 'ol/layer';
  7. import {Vector as VectorSource} from 'ol/source';
  8. import {HsConfig} from 'hslayers-ng/config.service';
  9. import {HsLayoutService} from 'hslayers-ng/components/layout/layout.service';
  10. import {HsMapService} from 'hslayers-ng/components/map/map.service';
  11. import {HsPanelContainerService} from 'hslayers-ng/components/layout/panels/panel-container.service';
  12. import {HsSidebarService} from 'hslayers-ng/components/sidebar/sidebar.service';
  13. import {AdjusterComponent} from './adjuster/adjuster.component';
  14. import {AdjusterEventService} from './adjuster/adjuster-event.service';
  15. import {AdjusterService} from './adjuster/adjuster.service';
  16. import {nuts} from './nuts';
  17. @Injectable({providedIn: 'root'})
  18. export class AppService {
  19. // https://colorbrewer2.org/?type=qualitative&scheme=Paired&n=12
  20. colorPalette = [
  21. '#a6cee3',
  22. '#1f78b4',
  23. '#b2df8a',
  24. '#33a02c',
  25. '#fb9a99',
  26. '#e31a1c',
  27. '#fdbf6f',
  28. '#ff7f00',
  29. '#cab2d6',
  30. '#6a3d9a',
  31. '#ffff99',
  32. '#b15928',
  33. ];
  34. nuts2style = new Style({
  35. stroke: new Stroke({
  36. color: '#000000',
  37. width: 0.5,
  38. }),
  39. });
  40. nuts2Layer = new VectorLayer({
  41. source: nuts.nuts2Source,
  42. editor: {editable: false},
  43. visible: false,
  44. style: this.nuts2style,
  45. title: 'NUTS2 regions',
  46. });
  47. nuts3Layer = new VectorLayer({
  48. source: nuts.nuts3Source,
  49. editor: {editable: false},
  50. visible: true,
  51. style: this.generateStyle(this.adjusterService.method),
  52. title: 'NUTS3 regions',
  53. });
  54. pilotsStyle = new Style({
  55. stroke: new Stroke({
  56. color: '#1d941d',
  57. width: 1.5,
  58. }),
  59. fill: new Fill({
  60. color: 'rgba(29, 148, 29, 0.2)',
  61. }),
  62. });
  63. pilotRegions = new VectorLayer({
  64. source: new VectorSource({
  65. format: new GeoJSON(),
  66. url: require('./data/pilot_regions.geojson').default,
  67. }),
  68. editor: {editable: false},
  69. visible: true,
  70. style: this.pilotsStyle,
  71. title: 'Polirural Pilot Regions',
  72. });
  73. serviceUrl: string;
  74. constructor(
  75. private adjusterService: AdjusterService,
  76. private adjusterEventService: AdjusterEventService,
  77. private hsConfig: HsConfig,
  78. private hsLayoutService: HsLayoutService,
  79. private hsMapService: HsMapService,
  80. private hsSidebarService: HsSidebarService,
  81. private hsPanelContainerService: HsPanelContainerService
  82. ) {
  83. this.serviceUrl = this.adjusterService.serviceBaseUrl + 'georeport/';
  84. this.nuts3Layer.set('popUp', {
  85. attributes: [
  86. {attribute: 'CNTR_CODE', label: 'Country'},
  87. {attribute: 'NUTS_NAME', label: 'Name'},
  88. {attribute: this.adjusterService.method /*, label: 'Cluster ID'*/},
  89. {
  90. attribute: 'NUTS_ID',
  91. label: 'Detailed report',
  92. displayFunction: (x) => {
  93. return `<a href="${this.serviceUrl}${x}" target="_blank">in a new page</a>.`;
  94. },
  95. },
  96. ],
  97. });
  98. this.pilotRegions.set('popUp', {
  99. attributes: [
  100. {attribute: 'NUTS_NAME', label: 'Region name'},
  101. //TODO: Uncomment when implemented in the rural-attractiveness-service
  102. /*{
  103. attribute: 'NUTS_ID',
  104. label: 'Pilot region details',
  105. displayFunction: (x) => {
  106. return `<a href="${this.serviceUrl}${x}" target="_blank">in a new page</a>.`;
  107. },
  108. },*/
  109. ],
  110. });
  111. this.adjusterEventService.clustersLoaded.subscribe(() => {
  112. this.colorPalette = this.generateRandomColorPalette(
  113. adjusterService.clusters.length
  114. );
  115. });
  116. this.adjusterEventService.methodChanged.subscribe((method) => {
  117. this.nuts3Layer.get('popUp').attributes[2].attribute = method;
  118. this.nuts3Layer.setStyle(this.generateStyle(this.adjusterService.method));
  119. });
  120. /* The order of pushes matter! */
  121. this.hsConfig.default_layers.push(this.nuts3Layer);
  122. this.hsConfig.default_layers.push(this.nuts2Layer);
  123. this.hsConfig.default_layers.push(this.pilotRegions);
  124. /*this.hsMapService
  125. .loaded()
  126. .then((map) => this.hsMapService.repopulateLayers([]));*/
  127. this.init();
  128. }
  129. init(): void {
  130. this.hsSidebarService.buttons.push({
  131. panel: 'adjuster',
  132. module: 'pra.adjuster',
  133. order: 0,
  134. title: 'Adjust factors',
  135. description: 'Adjust factors for computation',
  136. icon: 'icon-analytics-piechart',
  137. });
  138. this.hsPanelContainerService.create(AdjusterComponent, {});
  139. this.hsLayoutService.setDefaultPanel('adjuster');
  140. //this.hsLayoutService.sidebarRight = false;
  141. }
  142. /**
  143. * https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
  144. * @private
  145. * @description Only generates random colors if the current palette does not provide enough colors for all the clusters
  146. * @param {number} colorCount Number of colors to randomly generate
  147. * @returns {Array<Array<number> | string>} Array of RGB colors
  148. */
  149. private generateRandomColorPalette(colorCount: number) {
  150. const palette = this.colorPalette;
  151. const goldenRatioConjugate = 0.618033988749895;
  152. let i = palette.length;
  153. while (i < colorCount) {
  154. let h = Math.random();
  155. h += goldenRatioConjugate;
  156. h %= 1;
  157. h *= 360;
  158. palette.push(hsv2rgb(h, 0.5, 0.95));
  159. i++;
  160. }
  161. return palette;
  162. //return `rgba(${r}, ${g}, ${b}, 0.7)`;
  163. }
  164. /**
  165. * @description Function factory for generating style functions based on different clustering methods
  166. * @param {string} method currently selected method
  167. * @returns {function} style function
  168. */
  169. private generateStyle(method: string) {
  170. return (feature: Feature): Style => {
  171. if (isNaN(feature.get(method))) {
  172. return new Style({
  173. fill: new Fill({
  174. color: '#FFF',
  175. }),
  176. stroke: new Stroke({
  177. color: '#3399CC',
  178. width: 0.25,
  179. }),
  180. });
  181. } else {
  182. return new Style({
  183. fill: new Fill({
  184. color: this.colorPalette[feature.get(method) - 1],
  185. }),
  186. stroke: new Stroke({
  187. color: '#FFF',
  188. width: 0.25,
  189. }),
  190. });
  191. }
  192. };
  193. }
  194. }