Customize Tropical Cyclone Markers
Customize a tropical-cyclones
point layer provided by the Tropical module. The custom style will result in displaying storm category symbols and valid dates/times along the forecast track instead of basic points.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no'/>
<title>Xweather JavaScript SDK - Tropical Systems w/Custom Styles</title>
<script defer src="https://cdn.aerisapi.com/sdk/js/latest/aerisweather.min.js"></script>
<link rel="stylesheet" href="https://cdn.aerisapi.com/sdk/js/latest/aerisweather.css">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
width: 100%;
}
#map {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
window.onload = () => {
const aeris = new Xweather('CLIENT_ID', 'CLIENT_SECRET');
const utils = aeris.utils;
aeris.views().then(views => {
const map = new views.InteractiveMap(document.getElementById('map'), {
center: {
lat: 39.0,
lon: -95.5
},
zoom: 4,
layers: 'alerts,radar-est'
});
map.on('ready', () => {
aeris.modules().then((modules) => {
modules.tropical.utils().then((tropUtils) => {
// utility functions for styling
const getMarkerDate = (data) => {
let tzName = utils.get(data, 'profile.tz', 'UTC');
let dt = luxon.DateTime.fromISO(utils.get(data,'dateTimeISO')).setZone(tzName);
return dt.toFormat('h a ccc ZZZZ');
};
const getStormMarkerConfig = (data) => {
const {lat} = utils.get(data, 'loc');
const type = utils.get(data, 'details.stormCat');
const isCurrent = data.isCurrent;
const isForecast = data.isForecast;
const flipped = lat < 0 && tropUtils.flipForSouthernLat(type);
if (isCurrent || isForecast) {
const catTextStyle = {
value: (type === 'STY') ? 'S': type.replace(/[^\d]/g, ''),
anchor: 'start',
position: 'center',
translate: {
y: -2
},
size: 14,
color: '#ffffff',
autosize: false
};
const nameTextStyle = {
value: getMarkerDate(data),
anchor: 'start',
translate: {
y: 22
},
size: 11,
color: '#222222',
stroke: {
color: '#ffffff',
width: 2
},
autosize: false
}
let styles = {
className: 'marker-tropicalcyclone',
svg: {
image: {
url: (flipped && type === 'TD') ? tropUtils.icon(`${type}-flipped`): tropUtils.icon(type),
size: [25, 25],
transform: (flipped && type !== 'TD') ? 'scale(-1, 1) translate(-80, 0)': ''
},
text: [catTextStyle, nameTextStyle]
},
size: [80, 60],
zIndex: 50
};
if (isCurrent) {
styles = utils.extend({}, styles, {
svg: {
image: {
size: [34, 34]
},
text: [
utils.extend({}, catTextStyle, {
translate: {
y: -3
},
size: 20
}),
utils.extend({}, catTextStyle, {
value: utils.get(data, 'details.stormShortName'),
size: 16,
color: '#222222',
translate: {
y: 22
},
stroke: {
color: '#ffffff',
width: 3
}
})
]
},
size: [80, 80]
});
}
return styles;
}
return {
className: 'marker-tropicalcyclone',
svg: {
shape: {
type: 'circle',
fill: {
color: tropUtils.color(type)
},
stroke: {
color: '#ffffff',
width: 2
},
size: [14, 14]
},
text: data.label ? {
value: utils.get(data, 'details.stormShortName'),
anchor: 'start',
translate: {
y: 12
},
autosize: false
}: null
},
size: data.label ? [60, 40]: [14, 14],
zIndex: data.label ? 50: null
};
};
map.addModule(modules.tropical.Breakpoints);
map.addModule(modules.tropical.Systems, {
style: {
marker: (data) => getStormMarkerConfig(data, aeris.utils),
polyline: {
stroke: {
color: '#4685D0',
width: 3,
dashArray: '10 7 10 7'
}
},
polygon: {
fill: {
color: '#ffffff',
opacity: 0
},
stroke: {
color: '#666666',
width: 2,
opacity: 0.7
}
},
}
});
});
});
});
});
};
</script>
<script src="https://cdn.jsdelivr.net/npm/luxon@1.24.1/build/global/luxon.min.js"></script>
</body>
</html>