Skip to content

Instantly share code, notes, and snippets.

@woodyrew
Last active October 23, 2019 20:35
Show Gist options
  • Save woodyrew/eb682928c4e96572c9ead33ecf659c21 to your computer and use it in GitHub Desktop.
Save woodyrew/eb682928c4e96572c9ead33ecf659c21 to your computer and use it in GitHub Desktop.
Tides visualisation (d3 v5)
license: mit
[
{
"dawn": "2018-07-30 05:03",
"sunrise": "2018-07-30 05:43",
"sunset": "2018-07-30 21:06",
"dusk": "2018-07-30 21:45",
"dawnHours": 5.05,
"sunriseHours": 5.716666666666667,
"sunsetHours": 21.1,
"duskHours": 21.75,
"timezone": "BST (GMT +01:00)",
"tides": [
{
"id": 5,
"eventType": "HighWater",
"height": 5.084294785882167,
"localTime": "2018-07-29 20:12",
"hours": -3.8
},
{
"id": 6,
"eventType": "LowWater",
"height": 1.263425905164897,
"localTime": "2018-07-30 02:08",
"hours": 2.1333333333333333
},
{
"id": 7,
"eventType": "HighWater",
"height": 5.084294785882167,
"localTime": "2018-07-30 08:12",
"hours": 8.2
},
{
"id": 8,
"eventType": "LowWater",
"height": 1.3272020178080077,
"localTime": "2018-07-30 14:20",
"hours": 14.333333333333334
},
{
"id": 9,
"eventType": "HighWater",
"height": 5.275120164016581,
"localTime": "2018-07-30 20:23",
"hours": 20.383333333333333
},
{
"id": 10,
"eventType": "LowWater",
"height": 1.2890995548601911,
"localTime": "2018-07-31 02:38",
"hours": 26.633333333333333
}
],
"isoDate": "2018-07-30"
},
{
"dawn": "2018-07-31 05:05",
"sunrise": "2018-07-31 05:44",
"sunset": "2018-07-31 21:04",
"dusk": "2018-07-31 21:43",
"dawnHours": 5.083333333333333,
"sunriseHours": 5.733333333333333,
"sunsetHours": 21.066666666666666,
"duskHours": 21.716666666666665,
"timezone": "BST (GMT +01:00)",
"tides": [
{
"id": 5,
"eventType": "HighWater",
"height": 5.275120164016581,
"localTime": "2018-07-30 20:23",
"hours": -3.6166666666666667
},
{
"id": 6,
"eventType": "LowWater",
"height": 1.2890995548601911,
"localTime": "2018-07-31 02:38",
"hours": 2.6333333333333333
},
{
"id": 7,
"eventType": "HighWater",
"height": 5.039066738637026,
"localTime": "2018-07-31 08:48",
"hours": 8.8
},
{
"id": 8,
"eventType": "LowWater",
"height": 1.3723940177561327,
"localTime": "2018-07-31 14:48",
"hours": 14.8
},
{
"id": 9,
"eventType": "HighWater",
"height": 5.214076114347859,
"localTime": "2018-07-31 20:57",
"hours": 20.95
},
{
"id": 10,
"eventType": "LowWater",
"height": 1.3351434160040805,
"localTime": "2018-08-01 03:06",
"hours": 27.1
}
],
"isoDate": "2018-07-31"
},
{
"dawn": "2018-08-01 05:06",
"sunrise": "2018-08-01 05:46",
"sunset": "2018-08-01 21:03",
"dusk": "2018-08-01 21:42",
"dawnHours": 5.1,
"sunriseHours": 5.766666666666667,
"sunsetHours": 21.05,
"duskHours": 21.7,
"timezone": "BST (GMT +01:00)",
"tides": [
{
"id": 5,
"eventType": "HighWater",
"height": 5.214076114347859,
"localTime": "2018-07-31 20:57",
"hours": -3.05
},
{
"id": 6,
"eventType": "LowWater",
"height": 1.3351434160040805,
"localTime": "2018-08-01 03:06",
"hours": 3.1
},
{
"id": 7,
"eventType": "HighWater",
"height": 4.969648388399901,
"localTime": "2018-08-01 09:21",
"hours": 9.35
},
{
"id": 8,
"eventType": "LowWater",
"height": 1.4333129816113215,
"localTime": "2018-08-01 15:17",
"hours": 15.283333333333333
},
{
"id": 9,
"eventType": "HighWater",
"height": 5.135142606704623,
"localTime": "2018-08-01 21:28",
"hours": 21.466666666666665
},
{
"id": 10,
"eventType": "LowWater",
"height": 1.3995666491319219,
"localTime": "2018-08-02 03:36",
"hours": 27.6
}
],
"isoDate": "2018-08-01"
},
{
"dawn": "2018-08-02 05:08",
"sunrise": "2018-08-02 05:47",
"sunset": "2018-08-02 21:01",
"dusk": "2018-08-02 21:40",
"dawnHours": 5.133333333333334,
"sunriseHours": 5.783333333333333,
"sunsetHours": 21.016666666666666,
"duskHours": 21.666666666666668,
"timezone": "BST (GMT +01:00)",
"tides": [
{
"id": 4,
"eventType": "LowWater",
"height": 1.4333129816113215,
"localTime": "2018-08-01 15:17",
"hours": -8.716666666666667
},
{
"id": 5,
"eventType": "HighWater",
"height": 5.135142606704623,
"localTime": "2018-08-01 21:28",
"hours": -2.533333333333333
},
{
"id": 6,
"eventType": "LowWater",
"height": 1.3995666491319219,
"localTime": "2018-08-02 03:36",
"hours": 3.6
},
{
"id": 7,
"eventType": "HighWater",
"height": 4.887576605649308,
"localTime": "2018-08-02 09:54",
"hours": 9.9
},
{
"id": 8,
"eventType": "LowWater",
"height": 1.511950364784669,
"localTime": "2018-08-02 15:47",
"hours": 15.783333333333333
},
{
"id": 9,
"eventType": "HighWater",
"height": 5.043448845440969,
"localTime": "2018-08-02 22:00",
"hours": 22
},
{
"id": 10,
"eventType": "LowWater",
"height": 1.4887393954183692,
"localTime": "2018-08-03 04:08",
"hours": 28.133333333333333
}
],
"isoDate": "2018-08-02"
},
{
"dawn": "2018-08-03 05:10",
"sunrise": "2018-08-03 05:48",
"sunset": "2018-08-03 20:59",
"dusk": "2018-08-03 21:38",
"dawnHours": 5.166666666666667,
"sunriseHours": 5.8,
"sunsetHours": 20.983333333333334,
"duskHours": 21.633333333333333,
"timezone": "BST (GMT +01:00)",
"tides": [
{
"id": 4,
"eventType": "LowWater",
"height": 1.511950364784669,
"localTime": "2018-08-02 15:47",
"hours": -8.216666666666667
},
{
"id": 5,
"eventType": "HighWater",
"height": 5.043448845440969,
"localTime": "2018-08-02 22:00",
"hours": -2
},
{
"id": 6,
"eventType": "LowWater",
"height": 1.4887393954183692,
"localTime": "2018-08-03 04:08",
"hours": 4.133333333333334
},
{
"id": 7,
"eventType": "HighWater",
"height": 4.799076059897332,
"localTime": "2018-08-03 10:28",
"hours": 10.466666666666667
},
{
"id": 8,
"eventType": "LowWater",
"height": 1.6181705073400585,
"localTime": "2018-08-03 16:22",
"hours": 16.366666666666667
},
{
"id": 9,
"eventType": "HighWater",
"height": 4.934160883695531,
"localTime": "2018-08-03 22:36",
"hours": 22.6
},
{
"id": 10,
"eventType": "LowWater",
"height": 1.6109761748267435,
"localTime": "2018-08-04 04:48",
"hours": 28.8
}
],
"isoDate": "2018-08-03"
},
{
"dawn": "2018-08-04 05:11",
"sunrise": "2018-08-04 05:50",
"sunset": "2018-08-04 20:58",
"dusk": "2018-08-04 21:36",
"dawnHours": 5.183333333333334,
"sunriseHours": 5.833333333333333,
"sunsetHours": 20.966666666666665,
"duskHours": 21.6,
"timezone": "BST (GMT +01:00)",
"tides": [
{
"id": 4,
"eventType": "LowWater",
"height": 1.6181705073400585,
"localTime": "2018-08-03 16:22",
"hours": -7.633333333333334
},
{
"id": 5,
"eventType": "HighWater",
"height": 4.934160883695531,
"localTime": "2018-08-03 22:36",
"hours": -1.4
},
{
"id": 6,
"eventType": "LowWater",
"height": 1.6109761748267435,
"localTime": "2018-08-04 04:48",
"hours": 4.8
},
{
"id": 7,
"eventType": "HighWater",
"height": 4.706043430235942,
"localTime": "2018-08-04 11:10",
"hours": 11.166666666666666
},
{
"id": 8,
"eventType": "LowWater",
"height": 1.756779311842711,
"localTime": "2018-08-04 17:07",
"hours": 17.116666666666667
},
{
"id": 9,
"eventType": "HighWater",
"height": 4.805941558230959,
"localTime": "2018-08-04 23:24",
"hours": 23.4
},
{
"id": 10,
"eventType": "LowWater",
"height": 1.7584454521615127,
"localTime": "2018-08-05 05:38",
"hours": 29.633333333333333
}
],
"isoDate": "2018-08-04"
},
{
"dawn": "2018-08-05 05:13",
"sunrise": "2018-08-05 05:51",
"sunset": "2018-08-05 20:56",
"dusk": "2018-08-05 21:34",
"dawnHours": 5.216666666666667,
"sunriseHours": 5.85,
"sunsetHours": 20.933333333333334,
"duskHours": 21.566666666666666,
"timezone": "BST (GMT +01:00)",
"tides": [
{
"id": 4,
"eventType": "LowWater",
"height": 1.756779311842711,
"localTime": "2018-08-04 17:07",
"hours": -6.883333333333334
},
{
"id": 5,
"eventType": "HighWater",
"height": 4.805941558230959,
"localTime": "2018-08-04 23:24",
"hours": -0.6
},
{
"id": 6,
"eventType": "LowWater",
"height": 1.7584454521615127,
"localTime": "2018-08-05 05:38",
"hours": 5.633333333333334
},
{
"id": 7,
"eventType": "HighWater",
"height": 4.623828030269432,
"localTime": "2018-08-05 12:04",
"hours": 12.066666666666666
},
{
"id": 8,
"eventType": "LowWater",
"height": 1.9011711545013303,
"localTime": "2018-08-05 18:06",
"hours": 18.1
},
{
"id": 9,
"eventType": "HighWater",
"height": 4.684964599911539,
"localTime": "2018-08-06 00:25",
"hours": 24.416666666666668
},
{
"id": 10,
"eventType": "LowWater",
"height": 1.8775358300288445,
"localTime": "2018-08-06 06:49",
"hours": 30.816666666666666
}
],
"isoDate": "2018-08-05"
},
{
"dawn": "2018-08-06 05:15",
"sunrise": "2018-08-06 05:53",
"sunset": "2018-08-06 20:55",
"dusk": "2018-08-06 21:33",
"dawnHours": 5.25,
"sunriseHours": 5.883333333333334,
"sunsetHours": 20.916666666666668,
"duskHours": 21.55,
"timezone": "BST (GMT +01:00)",
"tides": [
{
"id": 4,
"eventType": "LowWater",
"height": 1.9011711545013303,
"localTime": "2018-08-05 18:06",
"hours": -5.9
},
{
"id": 5,
"eventType": "HighWater",
"height": 4.684964599911539,
"localTime": "2018-08-06 00:25",
"hours": 0.4166666666666667
},
{
"id": 6,
"eventType": "LowWater",
"height": 1.8775358300288445,
"localTime": "2018-08-06 06:49",
"hours": 6.816666666666666
},
{
"id": 7,
"eventType": "HighWater",
"height": 4.5989373284410195,
"localTime": "2018-08-06 13:12",
"hours": 13.2
},
{
"id": 8,
"eventType": "LowWater",
"height": 1.9606779158049166,
"localTime": "2018-08-06 19:31",
"hours": 19.516666666666666
},
{
"id": 9,
"eventType": "HighWater",
"height": 4.63545088718204,
"localTime": "2018-08-07 01:41",
"hours": 25.683333333333334
}
],
"isoDate": "2018-08-06"
},
{
"dawn": "2018-08-07 05:16",
"sunrise": "2018-08-07 05:54",
"sunset": "2018-08-07 20:53",
"dusk": "2018-08-07 21:31",
"dawnHours": 5.266666666666667,
"sunriseHours": 5.9,
"sunsetHours": 20.883333333333333,
"duskHours": 21.516666666666666,
"timezone": "BST (GMT +01:00)",
"tides": [
{
"id": 4,
"eventType": "LowWater",
"height": 1.9606779158049166,
"localTime": "2018-08-06 19:31",
"hours": -4.483333333333333
},
{
"id": 5,
"eventType": "HighWater",
"height": 4.63545088718204,
"localTime": "2018-08-07 01:41",
"hours": 1.6833333333333333
},
{
"id": 6,
"eventType": "LowWater",
"height": 1.8630872441847102,
"localTime": "2018-08-07 08:19",
"hours": 8.316666666666666
},
{
"id": 7,
"eventType": "HighWater",
"height": 4.693475523421634,
"localTime": "2018-08-07 14:30",
"hours": 14.5
},
{
"id": 8,
"eventType": "LowWater",
"height": 1.8379013862080984,
"localTime": "2018-08-07 21:01",
"hours": 21.016666666666666
},
{
"id": 9,
"eventType": "HighWater",
"height": 4.7257570257873365,
"localTime": "2018-08-08 03:07",
"hours": 27.116666666666667
}
],
"isoDate": "2018-08-07"
},
{
"dawn": "2018-08-08 05:18",
"sunrise": "2018-08-08 05:56",
"sunset": "2018-08-08 20:51",
"dusk": "2018-08-08 21:29",
"dawnHours": 5.3,
"sunriseHours": 5.933333333333334,
"sunsetHours": 20.85,
"duskHours": 21.483333333333334,
"timezone": "BST (GMT +01:00)",
"tides": [
{
"id": 3,
"eventType": "HighWater",
"height": 4.693475523421634,
"localTime": "2018-08-07 14:30",
"hours": -9.5
},
{
"id": 4,
"eventType": "LowWater",
"height": 1.8379013862080984,
"localTime": "2018-08-07 21:01",
"hours": -2.9833333333333334
},
{
"id": 5,
"eventType": "HighWater",
"height": 4.7257570257873365,
"localTime": "2018-08-08 03:07",
"hours": 3.1166666666666667
},
{
"id": 6,
"eventType": "LowWater",
"height": 1.6921006796799438,
"localTime": "2018-08-08 09:39",
"hours": 9.65
},
{
"id": 7,
"eventType": "HighWater",
"height": 4.916983174235054,
"localTime": "2018-08-08 15:46",
"hours": 15.766666666666667
},
{
"id": 8,
"eventType": "LowWater",
"height": 1.5798635615942196,
"localTime": "2018-08-08 22:16",
"hours": 22.266666666666666
},
{
"id": 9,
"eventType": "HighWater",
"height": 4.93400220016879,
"localTime": "2018-08-09 04:23",
"hours": 28.383333333333333
}
],
"isoDate": "2018-08-08"
},
{
"dawn": "2018-08-09 05:20",
"sunrise": "2018-08-09 05:57",
"sunset": "2018-08-09 20:49",
"dusk": "2018-08-09 21:27",
"dawnHours": 5.333333333333333,
"sunriseHours": 5.95,
"sunsetHours": 20.816666666666666,
"duskHours": 21.45,
"timezone": "BST (GMT +01:00)",
"tides": [
{
"id": 3,
"eventType": "HighWater",
"height": 4.916983174235054,
"localTime": "2018-08-08 15:46",
"hours": -8.233333333333333
},
{
"id": 4,
"eventType": "LowWater",
"height": 1.5798635615942196,
"localTime": "2018-08-08 22:16",
"hours": -1.7333333333333334
},
{
"id": 5,
"eventType": "HighWater",
"height": 4.93400220016879,
"localTime": "2018-08-09 04:23",
"hours": 4.383333333333334
},
{
"id": 6,
"eventType": "LowWater",
"height": 1.4357667772842604,
"localTime": "2018-08-09 10:48",
"hours": 10.8
},
{
"id": 7,
"eventType": "HighWater",
"height": 5.198223603172926,
"localTime": "2018-08-09 16:51",
"hours": 16.85
},
{
"id": 8,
"eventType": "LowWater",
"height": 1.2690472959643124,
"localTime": "2018-08-09 23:21",
"hours": 23.35
},
{
"id": 9,
"eventType": "HighWater",
"height": 5.167444948662426,
"localTime": "2018-08-10 05:26",
"hours": 29.433333333333334
}
],
"isoDate": "2018-08-09"
},
{
"dawn": "2018-08-10 05:22",
"sunrise": "2018-08-10 05:59",
"sunset": "2018-08-10 20:48",
"dusk": "2018-08-10 21:25",
"dawnHours": 5.366666666666666,
"sunriseHours": 5.983333333333333,
"sunsetHours": 20.8,
"duskHours": 21.416666666666668,
"timezone": "BST (GMT +01:00)",
"tides": [
{
"id": 3,
"eventType": "HighWater",
"height": 5.198223603172926,
"localTime": "2018-08-09 16:51",
"hours": -7.15
},
{
"id": 4,
"eventType": "LowWater",
"height": 1.2690472959643124,
"localTime": "2018-08-09 23:21",
"hours": -0.65
},
{
"id": 5,
"eventType": "HighWater",
"height": 5.167444948662426,
"localTime": "2018-08-10 05:26",
"hours": 5.433333333333334
},
{
"id": 6,
"eventType": "LowWater",
"height": 1.1600820417299513,
"localTime": "2018-08-10 11:49",
"hours": 11.816666666666666
},
{
"id": 7,
"eventType": "HighWater",
"height": 5.460104451400478,
"localTime": "2018-08-10 17:49",
"hours": 17.816666666666666
},
{
"id": 8,
"eventType": "LowWater",
"height": 0.9702513648430551,
"localTime": "2018-08-11 00:19",
"hours": 24.316666666666666
},
{
"id": 9,
"eventType": "HighWater",
"height": 5.363182174503781,
"localTime": "2018-08-11 06:23",
"hours": 30.383333333333333
}
],
"isoDate": "2018-08-10"
},
{
"dawn": "2018-08-11 05:23",
"sunrise": "2018-08-11 06:00",
"sunset": "2018-08-11 20:46",
"dusk": "2018-08-11 21:23",
"dawnHours": 5.383333333333334,
"sunriseHours": 6,
"sunsetHours": 20.766666666666666,
"duskHours": 21.383333333333333,
"timezone": "BST (GMT +01:00)",
"tides": [
{
"id": 3,
"eventType": "HighWater",
"height": 5.460104451400478,
"localTime": "2018-08-10 17:49",
"hours": -6.183333333333334
},
{
"id": 4,
"eventType": "LowWater",
"height": 0.9702513648430551,
"localTime": "2018-08-11 00:19",
"hours": 0.31666666666666665
},
{
"id": 5,
"eventType": "HighWater",
"height": 5.363182174503781,
"localTime": "2018-08-11 06:23",
"hours": 6.383333333333334
},
{
"id": 6,
"eventType": "LowWater",
"height": 0.915212670981172,
"localTime": "2018-08-11 12:43",
"hours": 12.716666666666667
},
{
"id": 7,
"eventType": "HighWater",
"height": 5.658848095409964,
"localTime": "2018-08-11 18:42",
"hours": 18.7
},
{
"id": 8,
"eventType": "LowWater",
"height": 0.915212670981172,
"localTime": "2018-08-12 00:43",
"hours": 24.716666666666665
}
],
"isoDate": "2018-08-11"
}
]
<!DOCTYPE html>
<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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment