This example shows how the <Vector>
source can be used to render a feature
that is updated with changes to a component's state variables. In this example
a single feature is rendered with a polygon geometry representing the solar
terminator (dark where it is night and light where it is day).
The day
and hour
state variables are controlled by the sliders on the map.
A useEffect
hook is called when these values change to calculate a new polygon
geometry representing the night. The vector source is constructed with a single
feature whose geometry is updated with this new polygon using the
feature.setGeometry()
method.
import Feature from 'ol/Feature.js';
import Layer from '@planet/maps/layer/Vector.js';
import Map from '@planet/maps/Map.js';
import OSM from '@planet/maps/source/OSM.js';
import React, {useEffect, useState} from 'react';
import Source from '@planet/maps/source/Vector.js';
import TileLayer from '@planet/maps/layer/WebGLTile.js';
import View from '@planet/maps/View.js';
import {getNightGeometry} from './solar.js';
const now = new Date();
// reuse a single feature, update the geometry as needed
const feature = new Feature();
/**
* @param {Date} date Input date.
* @return {number} The day number (starting with 1).
*/
function getDayOfYear(date) {
return (
1 +
Math.floor((date.getTime() - Date.UTC(date.getUTCFullYear())) / 86400000)
);
}
/**
* @param {number} UTC year.
* @param {number} UTC day number (starting with 1).
* @param {number} UTC hour.
* @return {Date} The date.
*/
function getDate(year, day, hour) {
const date = new Date(Date.UTC(year));
date.setUTCDate(day);
date.setUTCHours(hour, 60 * (hour % 1));
return date;
}
function SolarTerminator() {
const [day, updateDay] = useState(getDayOfYear(now));
const [hour, updateHour] = useState(
now.getUTCHours() + now.getUTCMinutes() / 60,
);
useEffect(() => {
const date = getDate(now.getUTCFullYear(), day, hour);
const polygon = getNightGeometry(date, 'EPSG:3857');
feature.setGeometry(polygon);
}, [day, hour]);
return (
<>
<Map>
<View options={{center: [0, 0], zoom: 1}} />
<TileLayer>
<OSM />
</TileLayer>
<Layer style={{'fill-color': '#00000033'}}>
<Source options={{features: [feature]}} />
</Layer>
</Map>
<div style={{width: 150, position: 'absolute', top: 10, right: 10}}>
<b>{getDate(now.getUTCFullYear(), day, hour).toUTCString()}</b>
<hr />
<label>
Day of the year
<input
type="range"
min={0}
max={366}
style={{width: '100%'}}
value={day}
onChange={event => updateDay(parseInt(event.target.value))}
/>
</label>
<label>
Hour of the Day
<input
type="range"
min={0}
max={24}
step={1 / 60}
style={{width: '100%'}}
value={hour}
onChange={event => updateHour(parseFloat(event.target.value))}
/>
</label>
</div>
</>
);
}
export default SolarTerminator;