Advertisement
Guest User

map-party

a guest
Jun 18th, 2019
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.47 KB | None | 0 0
  1. import {
  2. Component,
  3. EventEmitter,
  4. Input,
  5. Output,
  6. OnDestroy,
  7. OnChanges,
  8. SimpleChanges,
  9. OnInit
  10. } from '@angular/core';
  11. import { MapService } from 'src/app/core/services/map/map.service';
  12. import { Location } from 'src/app/core/models/Location';
  13. import { GeoJson, FeatureCollection } from 'src/app/core/models/mapbox/Map';
  14. import { Feature } from 'src/app/core/models/mapbox/MapboxReverseGeocodingResponse';
  15. import { environment } from 'src/environments/environment';
  16. import { Geolocation } from '@ionic-native/geolocation/ngx';
  17. import * as mapboxgl from 'mapbox-gl';
  18. import * as MapboxGeocoder from '@mapbox/mapbox-gl-geocoder';
  19. import { BikePartyToastrService } from 'src/app/core/services/toastr/toastr.service';
  20.  
  21. const mapStyle = 'mapbox://styles/mapbox/outdoors-v9';
  22. const defaultCoordinates = {
  23. latitude: 59.3293,
  24. longitude: 18.0686
  25. }; // Stockholm coordinates
  26.  
  27. // NOTE: For iOS you have to add this configuration to your configuration.xml file
  28. // <edit-config file="*-Info.plist" mode="merge" target="NSLocationWhenInUseUsageDescription">
  29. // <string>We use your location for full functionality of certain app features.</string>
  30. // </edit-config>
  31.  
  32. @Component({
  33. selector: 'app-map',
  34. templateUrl: './map.component.html',
  35. styleUrls: ['./map.component.scss']
  36. })
  37. export class MapComponent implements OnChanges, OnDestroy {
  38. @Input() locations: Location[];
  39. @Input() isReadOnly = false;
  40. @Input() mapName = 'map';
  41. @Output() addressEvent = new EventEmitter();
  42. @Output() totalTripDistanceEvent = new EventEmitter();
  43.  
  44. map: mapboxgl.Map;
  45. markerSource: any;
  46. routeSource: any;
  47.  
  48. constructor(
  49. private mapService: MapService,
  50. private geolocation: Geolocation,
  51. private toastr: BikePartyToastrService
  52. ) {}
  53.  
  54. ngOnChanges(changes: SimpleChanges) {
  55. this.locations = changes['locations']
  56. ? changes['locations'].currentValue
  57. : this.locations;
  58. this.mapName = changes['mapName']
  59. ? changes['mapName'].currentValue
  60. : this.mapName;
  61. this.isReadOnly = changes['isReadOnly']
  62. ? changes['isReadOnly'].currentValue
  63. : this.isReadOnly;
  64.  
  65. if (this.locations) {
  66. this.buildMap(this.locations, this.mapName);
  67. } else {
  68. this.geolocation
  69. .getCurrentPosition()
  70. .then(position => {
  71. this.buildMap([position.coords], this.mapName);
  72. })
  73. .catch(() => {
  74. this.buildMap([defaultCoordinates], this.mapName);
  75. this.toastr.info(
  76. 'To have a complete experience of the app, please turn on the location.'
  77. );
  78. });
  79. }
  80. }
  81.  
  82. ngOnDestroy() {
  83. if (this.map) {
  84. this.map.remove();
  85. }
  86. }
  87.  
  88. buildMap(locations: Location[], mapName: string) {
  89. const averageLongitude =
  90. locations.map(x => +x.longitude).reduce((a, b) => a + b, 0) /
  91. locations.length;
  92. const averageLatitude =
  93. locations.map(x => +x.latitude).reduce((a, b) => a + b, 0) /
  94. locations.length;
  95.  
  96. setTimeout(() => {
  97. this.map = new mapboxgl.Map({
  98. container: mapName,
  99. style: mapStyle,
  100. zoom: 14,
  101. center: [averageLongitude, averageLatitude],
  102. attributionControl: false
  103. });
  104.  
  105. this.map.on('load', event => {
  106. if (this.locations) {
  107. this.initMarkers(this.locations);
  108. }
  109.  
  110. if (locations.length > 1) {
  111. this.initRoute(locations);
  112. }
  113. });
  114.  
  115. if (!this.isReadOnly) {
  116. this.initMapControls();
  117. }
  118.  
  119. this.map.resize();
  120. }, 1); // this is to fix map bug upon initialization
  121. }
  122.  
  123. initMapControls() {
  124. this.map.addControl(
  125. new MapboxGeocoder({
  126. accessToken: environment.mapbox.accessToken,
  127. mapboxgl: mapboxgl,
  128. markers: true
  129. })
  130. );
  131.  
  132. this.map.on('click', event => {
  133. const lng = event.lngLat.lng;
  134. const lat = event.lngLat.lat;
  135.  
  136. this.addMarker(lng, lat);
  137.  
  138. console.log('lng', lng);
  139. console.log('lat', lat);
  140.  
  141. this.mapService
  142. .getPointOfInterest(event.lngLat.lng, event.lngLat.lat)
  143. .then(places => {
  144. const location = this.parseFeatureToLocation(places.features[0]);
  145. location.latitude = lat;
  146. location.longitude = lng;
  147. this.addressEvent.emit(location);
  148. })
  149. .catch(() => {});
  150. });
  151. }
  152.  
  153. initMarkers(locations: Location[]) {
  154. if (!this.map.getSource('markers')) {
  155. this.map.addSource('markers', {
  156. type: 'geojson',
  157. data: {
  158. type: 'FeatureCollection',
  159. features: []
  160. }
  161. });
  162. }
  163. this.markerSource = this.map.getSource('markers');
  164.  
  165. if (locations) {
  166. const markers = [];
  167. locations.forEach(location => {
  168. if (location.latitude) {
  169. markers.push(
  170. new GeoJson([location.longitude, location.latitude], 'Point', {
  171. message: location.definition
  172. })
  173. );
  174. }
  175. });
  176. this.markerSource.setData(new FeatureCollection(markers));
  177. }
  178.  
  179. this.map.addLayer({
  180. id: 'location',
  181. source: 'markers',
  182. type: 'symbol',
  183. layout: {
  184. 'text-field': '{message}',
  185. 'text-size': 15,
  186. 'text-transform': 'uppercase',
  187. 'icon-image': 'star-15',
  188. 'text-offset': [0, 1.5]
  189. },
  190. paint: {
  191. 'text-color': 'red',
  192. 'text-halo-color': '#fff',
  193. 'text-halo-width': 2
  194. }
  195. });
  196. }
  197. initRoute(locations: Location[]) {
  198. if (!this.map.getSource('route')) {
  199. this.map.addSource('route', {
  200. type: 'geojson',
  201. data: {
  202. type: 'Feature',
  203. geometry: null
  204. }
  205. });
  206. }
  207. this.routeSource = this.map.getSource('route');
  208.  
  209. const wayPoints = [];
  210. locations.forEach((location, index) => {
  211. if (index < locations.length && location.latitude) {
  212. wayPoints.push(location.longitude + ',' + location.latitude);
  213. }
  214. });
  215.  
  216. this.mapService
  217. .getRouteCoordinates(wayPoints.filter(Boolean).join(';'))
  218. .then(response => {
  219. this.routeSource.setData({
  220. type: 'Feature',
  221. geometry: {
  222. type: 'LineString',
  223. coordinates: response.routes[0].geometry.coordinates
  224. }
  225. });
  226. this.totalTripDistanceEvent.emit(response.routes[0].distance);
  227. });
  228.  
  229. if (!this.map.getLayer('routeline-active')) {
  230. this.map.addLayer(
  231. {
  232. id: 'routeline-active',
  233. type: 'line',
  234. source: 'route',
  235. layout: {
  236. 'line-join': 'round',
  237. 'line-cap': 'round'
  238. },
  239. paint: {
  240. 'line-color': '#3887be',
  241. 'line-width': ['interpolate', ['linear'], ['zoom'], 12, 3, 22, 12]
  242. }
  243. },
  244. 'waterway-label'
  245. );
  246. }
  247. }
  248.  
  249. addMarker(lng: number, lat: number): void {
  250. const marker = new GeoJson([lng, lat], 'Point', { message: '' });
  251. const data = new FeatureCollection([marker]);
  252. this.markerSource.setData(data);
  253. }
  254.  
  255. parseFeatureToLocation(data: Feature): Location {
  256. return {
  257. postalCode: data.context.find(x => x.id.includes('postcode')).text || '',
  258. street: data.properties.address || '',
  259. city: data.context.find(x => x.id.includes('place')).text || '',
  260. country: data.context.find(x => x.id.includes('country')).text || '',
  261. name: data.text || ''
  262. };
  263. }
  264. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement