Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

draft: feat(studio): display typhoon track #245

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,215 changes: 2,008 additions & 207 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"highcharts": "^9.3.0",
"highcharts-angular": "^2.10.0",
"mapbox-gl": "^2.5.1",
"mapbox-gl-circle": "^1.6.5",
"ngx-google-analytics": "^11.2.1",
"rxjs": "~6.6.0",
"tslib": "^2.3.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import mapboxgl, {
Map,
Marker,
} from 'mapbox-gl';
import { MapboxCircle } from 'mapbox-gl-circle';
import { environment } from '@env/environment';
import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css';
import { combineLatest, fromEvent, Subject } from 'rxjs';
Expand Down Expand Up @@ -50,6 +51,7 @@ import {
HazardType,
LandslideHazards,
PH_DEFAULT_CENTER,
TyphoonTrackType,
VolcanoType,
WeatherSatelliteState,
WeatherSatelliteType,
Expand Down Expand Up @@ -135,6 +137,7 @@ export class MapPlaygroundComponent implements OnInit, OnDestroy {
this.initSensors();
this.initVolcanoes();
this.initWeatherSatelliteLayers();
this.initTyphoonTrackLayers();
this.showContourMaps();
});
}
Expand Down Expand Up @@ -701,6 +704,316 @@ export class MapPlaygroundComponent implements OnInit, OnDestroy {
);
}

initTyphoonTrackLayers() {
// 0 - declare the source json files
const typhoonLayersSourceFiles: Record<TyphoonTrackType, { url: string }> =
{
'typhoon-track': {
url: 'https://upri-noah.s3.ap-southeast-1.amazonaws.com/typhoon_track/typhoon.geojson',
},
PAR: {
url: 'https://upri-noah.s3.ap-southeast-1.amazonaws.com/par/PAR.geojson',
},
};

const allShown$ = this.pgService.typhoonTrackGroupShown$.pipe(
distinctUntilChanged()
);

// 1 - load the geojson files (add sources/layers)
Object.keys(typhoonLayersSourceFiles).forEach(
(typhoonTrackType: TyphoonTrackType) => {
const typhoonObjData = typhoonLayersSourceFiles[typhoonTrackType];

// 2 - load typhoon track layers icon
const _this = this;
this.map.loadImage('assets/icons/typhoon.png', (error, image) => {
if (error) throw error;
// 3 - add typhoon track icon
_this.map.addImage('custom-marker', image);

// 4 - add source
const typhoonMapSource = `${typhoonTrackType}-map-source`;
_this.map.addSource(typhoonMapSource, {
type: 'geojson',
data: typhoonObjData.url,
});

// 5 - add point layer
const layerID = `${typhoonTrackType}-map-layer`;
this.map.addLayer({
id: 'typhoon-track-icon',
type: 'symbol',
source: typhoonMapSource,
paint: {
'icon-opacity': 1,
'text-opacity': 1,
'text-color':
_this.mapStyle === 'terrain' ? '#333333' : '#ffffff',
'text-halo-color':
_this.mapStyle === 'terrain'
? 'rgba(255, 255, 255, 1)'
: 'rgba(0, 0, 0, 1)',
'text-halo-width': 0.5,
'text-halo-blur': 0.5,
},
layout: {
'icon-image': 'custom-marker',
'icon-allow-overlap': true,
'icon-size': ['interpolate', ['linear'], ['zoom'], 4, 0.03],
// 'text-size': ['interpolate', ['linear'], ['zoom'], 4, 0.03],
'text-optional': true,
'text-anchor': 'top',
'text-font': ['DIN Pro Bold', 'Arial Unicode MS Bold'],
'text-field': [
'concat',
['get', 'typhoon_name'],
['concat', '\n(DATE: ', ['get', 'datetime'], ')'],
],
'text-offset': [0, 2],
'text-size': 12,
'text-letter-spacing': 0.1,
},
});
// 6 -Add line layer
this.map.addLayer({
id: 'typhoon-track-line',
type: 'line',
source: typhoonMapSource,
paint: {
'line-color': '#bdd9f1',
'line-width': 1.5,
'line-dasharray': [2, 1],
},
filter: ['==', 'name', 'typhoon-track'],
});
// 7 - Add PAR layer
this.map.addLayer({
id: 'par',
type: 'line',
source: typhoonMapSource,
paint: {
'line-color': 'white',
'line-width': 2,
},
filter: ['==', 'name', 'PAR'],
});

// 8 - listen to the values from the store
const typhoonTrack$ = this.pgService
.getTyphoonTrack$(typhoonTrackType)
.pipe(shareReplay(1));

combineLatest([allShown$, typhoonTrack$])
.pipe(takeUntil(this._unsub), takeUntil(this._changeStyle))
.subscribe(([allShown, typhoonTrack]) => {
let newOpacity = 0;
if (typhoonTrack.shown && allShown) {
newOpacity = typhoonTrack.opacity / 100;
this.map.flyTo({
center: PH_DEFAULT_CENTER,
zoom: 4,
essential: true,
});
}
this.map.setPaintProperty(
'typhoon-track-icon',
'icon-opacity',
newOpacity
);
this.map.setPaintProperty(
'typhoon-track-line',
'line-opacity',
newOpacity
);
this.map.setPaintProperty('par', 'line-opacity', newOpacity);
this.map.setPaintProperty(
'typhoon-track-icon',
'text-opacity',
newOpacity
);
});
});
}
);
}

// initTyphoonTrackLayers() {
// this.map.loadImage('assets/icons/typhoon.png', (error, image) => {
// if (error) throw error;
// this.map.addImage('custom-marker', image);
// });
// this.map.addSource('typhoonTrack', {
// type: 'geojson',
// // Use a URL for the value for the `data` property.
// data: 'https://upri-noah.s3.ap-southeast-1.amazonaws.com/typhoon_track/typhoon.geojson',
// });
// this.map.addSource('PAR', {
// type: 'geojson',
// data: 'https://upri-noah.s3.ap-southeast-1.amazonaws.com/par/PAR.geojson',
// });

// // Add point layer
// this.map.addLayer({
// id: 'typhoon-track-icon',
// type: 'symbol',
// source: 'typhoonTrack',
// layout: {
// 'icon-image': 'custom-marker',
// 'icon-allow-overlap': true,
// 'icon-size': ['interpolate', ['linear'], ['zoom'], 4, 0.03],
// },
// });
// // Add radius layer
// // this.map.addLayer({
// // id: 'typhoon-track-radius',
// // type: 'circle',
// // source: 'typhoonTrack',
// // paint: {
// // 'circle-color': '#bdd9f1',
// // 'circle-radius': 30,
// // 'circle-opacity': 0.1,
// // },
// // });

// // Add radius layer
// // this.map.addLayer({
// // id: 'typhoon-track-radius',
// // type: 'circle',
// // source: 'typhoonTrack',
// // paint: {
// // 'circle-color': '#bdd9f1',
// // 'circle-radius': 30,
// // 'circle-opacity': 0.1,
// // },
// // });

// // Add line layer
// this.map.addLayer({
// id: 'typhoon-track-line',
// type: 'line',
// source: 'typhoonTrack',
// paint: {
// 'line-color': '#bdd9f1',
// 'line-width': 1.5,
// 'line-dasharray': [2, 1],
// },
// filter: ['==', 'name', 'typhoon-track'],
// });
// // Add PAR layer
// this.map.addLayer({
// id: 'par',
// type: 'line',
// source: 'PAR',
// paint: {
// 'line-color': 'white',
// 'line-width': 2,
// },
// });

// // const myCircle = new MapboxCircle({lat: 16.4, lng: 110.4}, 25000, {
// // editable: true,
// // minRadius: 1500,
// // fillColor: '#29AB87'
// // }).addTo(this.map);

// // Add probability radius per point
// // const fetchData = this.pgService.getTyphoonData();
// // console.log(fetchData + 'test data');

// // for (const feature of fetchData.features) {
// // const rad = feature.properties.radius
// // console.log(rad);
// // let myCircle = new MapboxCircle({lat: feature.geometry.coordinates[1], lng: feature.geometry.coordinates[0]}, 300, {
// // editable: false,
// // fillColor: '#29AB87'
// // }).addTo(this.map).setRadius(rad); //
// // };

// this.pgService.typhoonTrack$
// .pipe(pluck('opacity'), distinctUntilChanged())
// .pipe(takeUntil(this._unsub), takeUntil(this._changeStyle))
// .subscribe((opacity) => {
// this.map.setPaintProperty(
// 'typhoon-track-icon',
// 'icon-opacity',
// opacity / 100
// );
// this.map.setPaintProperty(
// 'typhoon-track-line',
// 'line-opacity',
// opacity / 100
// );
// });

// const popUp = new mapboxgl.Popup({
// closeButton: true,
// closeOnClick: false,
// });
// const _this = this;

// this.pgService.typhoonTrack$
// .pipe(
// distinctUntilChanged((prev, next) => prev.shown === next.shown),
// takeUntil(this._unsub),
// takeUntil(this._changeStyle)
// )
// .subscribe((typhoonTrack) => {
// let newOpacity = 0;
// if (typhoonTrack.shown) {
// newOpacity = typhoonTrack.opacity / 100;
// this.map.flyTo({
// center: PH_DEFAULT_CENTER,
// zoom: 4,
// essential: true,
// });
// const fetchData = this.map.on('mouseover', (e) => {
// const coordinates = (
// e.features[0].geometry as any
// ).coordinates.slice();
// const dateTime = e.features[0].properties.datetime;
// const typhoonName = e.features[0].properties.typhoon_name;
// const typhoonClass = e.features[0].properties.typhoon_class;

// while (Math.abs(e.lnglat.lng - coordinates[0]) > 180) {
// coordinates[0] += e.lnglat.lng > coordinates[0] ? 360 : -360;
// }

// _this.map.getCanvas().style.cursor = 'pointer';
// popUp
// .setLngLat(coordinates)
// .setHTML(
// `
// <div style="color: #333333;">
// <div><strong>#${typhoonName}</strong></div>
// <div>Date: ${dateTime}</div>
// <div>Class: ${typhoonClass}</div>
// </div>
// `
// )
// .addTo(_this.map);
// });
// } else {
// popUp.remove();
// this.map.on('mouseover', (e) => {
// _this.map.getCanvas().style.cursor = '';
// popUp.remove();
// });
// }
// this.map.setPaintProperty(
// 'typhoon-track-icon',
// 'icon-opacity',
// newOpacity
// );
// this.map.setPaintProperty(
// 'typhoon-track-line',
// 'line-opacity',
// newOpacity
// );
// this.map.setPaintProperty('par', 'line-opacity', newOpacity);
// });
// }

showContourMaps() {
const contourMapImages = {
'1hr': {
Expand Down
Loading