Built with blockbuilder.org
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0;
max-width: 600px;
}
svg {
border: 1px solid #666;
height: auto;
margin-left: 10px;
width: calc(100% - 20px);
}
</style>
</head>
<body>
<h1>Tides Visualisation</h1>
<svg id="tides" viewBox="0 0 600 150"></svg>
<label for="day_select">Day</label>
<input type="range" id="day_select" name="day_select"
min="0" max="0" value="0" />
<p>Date: <strong id="human_date"></strong>
<script>
const dimension = {
witdth: 600,
height: 150
};
const margin = {
bottom: 20
};
const colour = {
night: '#858585',
dim: '#ccc',
day: '#e3ebec',
seaIn: '#20783b',
seaOut: '#38ab5b'
};
d3.json('dateTides.json').then(dateTides=> {
const maxTide =
Math.ceil(
dateTides.reduce((maxTide, date) => {
const dateMax = date.tides.reduce(
(max, tide) => (tide.height > max ? tide.height : max),
0
);
return dateMax > maxTide ? dateMax : maxTide;
}, 0)
) + 1;
const xScale = d3
.scaleLinear()
.domain([0, 24])
.range([0, dimension.witdth]);
const yScale = d3
.scaleLinear()
.domain([0, maxTide])
.range([dimension.height - margin.bottom, 0]);
const valueLine = d3
.area()
.x(d => xScale(d.hours))
.y1(d => yScale(d.height))
.y0(yScale(0))
.curve(d3.curveCardinal);
const svg = d3.select('#tides');
const daySelect = d3.select('#day_select');
const humanDate = d3.select('#human_date');
// Setup the Range slider
daySelect.attr('max', dateTides.length - 1);
const render = today => {
const {
isoDate,
dawnHours,
sunriseHours,
sunsetHours,
duskHours,
tides
} = today;
const humanDateText = moment(isoDate).format('dddd Do MMMM YYYY');
humanDate.text(humanDateText);
console.log('today.tides', humanDateText);
console.table(today.tides);
const morning = svg
.selectAll('.morning')
.data(
[
{ id: 'sunrise', hours: sunriseHours, colourID: 'dim' },
{ id: 'dawn', hours: dawnHours, colourID: 'night' }
],
d => d.id
);
// Add dawn
const morningRects = morning
.enter()
.append('rect')
.attr('class', 'morning')
.attr('x', 0)
.attr('y', 0)
.attr('height', yScale(0));
// .attr('width', d => xScale(d.hours))
morningRects
.merge(morning)
.transition()
.attr('width', d => xScale(d.hours))
.attr('fill', d => colour[d.colourID]);
const evening = svg
.selectAll('.evening')
.data(
[
{ id: 'sunset', hours: sunsetHours, colourID: 'dim' },
{ id: 'dusk', hours: duskHours, colourID: 'night' }
],
d => d.id
);
const eveningRects = evening
.enter()
.append('rect')
.attr('class', 'evening')
.attr('x', xScale(24))
.attr('y', 0)
.attr('height', yScale(0));
// .attr('width', d => xScale(d.hours))
eveningRects
.merge(evening)
.transition()
.attr('x', d => xScale(d.hours))
.attr('width', d => xScale(24 - d.hours))
.attr('fill', d => colour[d.colourID]);
// Add chart area
let chart = svg.selectAll('.line').data([tides], d => d.id);
const chartEnter = chart
.enter()
.append('path')
.attr('class', 'line')
.style('fill', 'green');
chart.exit().remove();
chart = chartEnter
.merge(chart)
// .transition()
.attr('d', valueLine);
};
// Set Day background
svg
.append('rect')
.attr('class', 'day')
.attr('x', 0)
.attr('y', 0)
.attr('width', xScale(24))
.attr('height', yScale(0))
.attr('fill', colour.day);
// Add the x axis
svg
.append('g')
.attr('class', 'tick')
.attr('transform', `translate(0,${dimension.height - margin.bottom})`)
.call(d3.axisBottom(xScale).tickSizeOuter(0));
// Remove 0 and 24 numbers from scale
svg
.selectAll('.tick')
.filter(d => d === 0 || d === 24)
.remove();
// Handler for range input change
const rangeTrigger = () => {
const index = daySelect.property('value');
const date = dateTides[index];
render(date);
};
daySelect.on('input', rangeTrigger);
rangeTrigger();
});
</script>
</body>
https://d3js.org/d3.v5.min.js
https://momentjs.com/downloads/moment.min.js