add hourly graph
This commit is contained in:
parent
0331de8b8a
commit
1a7734b620
|
@ -77,6 +77,7 @@ const mjsSources = [
|
||||||
'server/scripts/modules/icons.mjs',
|
'server/scripts/modules/icons.mjs',
|
||||||
'server/scripts/modules/extendedforecast.mjs',
|
'server/scripts/modules/extendedforecast.mjs',
|
||||||
'server/scripts/modules/hourly.mjs',
|
'server/scripts/modules/hourly.mjs',
|
||||||
|
'server/scripts/modules/hourly-graph.mjs',
|
||||||
'server/scripts/modules/latestobservations.mjs',
|
'server/scripts/modules/latestobservations.mjs',
|
||||||
'server/scripts/modules/localforecast.mjs',
|
'server/scripts/modules/localforecast.mjs',
|
||||||
'server/scripts/modules/radar.mjs',
|
'server/scripts/modules/radar.mjs',
|
||||||
|
|
BIN
server/images/BackGround1_1_Chart.png
Normal file
BIN
server/images/BackGround1_1_Chart.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.6 KiB |
|
@ -192,8 +192,10 @@ const EnterFullScreen = () => {
|
||||||
resize();
|
resize();
|
||||||
UpdateFullScreenNavigate();
|
UpdateFullScreenNavigate();
|
||||||
|
|
||||||
// change hover text
|
// change hover text and image
|
||||||
document.getElementById('ToggleFullScreen').title = 'Exit fullscreen';
|
const img = document.getElementById('ToggleFullScreen');
|
||||||
|
img.src = 'images/nav/ic_fullscreen_exit_white_24dp_1x.png';
|
||||||
|
img.title = 'Exit fullscreen';
|
||||||
};
|
};
|
||||||
|
|
||||||
const ExitFullscreen = () => {
|
const ExitFullscreen = () => {
|
||||||
|
@ -214,8 +216,10 @@ const ExitFullscreen = () => {
|
||||||
document.msExitFullscreen();
|
document.msExitFullscreen();
|
||||||
}
|
}
|
||||||
resize();
|
resize();
|
||||||
// change hover text
|
// change hover text and image
|
||||||
document.getElementById('ToggleFullScreen').title = 'Enter fullscreen';
|
const img = document.getElementById('ToggleFullScreen');
|
||||||
|
img.src = 'images/nav/ic_fullscreen_white_24dp_1x.png';
|
||||||
|
img.title = 'Enter fullscreen';
|
||||||
};
|
};
|
||||||
|
|
||||||
const btnNavigateMenuClick = () => {
|
const btnNavigateMenuClick = () => {
|
||||||
|
|
|
@ -171,7 +171,7 @@ class Almanac extends WeatherDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
// register display
|
// register display
|
||||||
const display = new Almanac(7, 'almanac');
|
const display = new Almanac(8, 'almanac');
|
||||||
registerDisplay(display);
|
registerDisplay(display);
|
||||||
|
|
||||||
export default display.getSun.bind(display);
|
export default display.getSun.bind(display);
|
||||||
|
|
|
@ -161,4 +161,4 @@ class ExtendedForecast extends WeatherDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
// register display
|
// register display
|
||||||
registerDisplay(new ExtendedForecast(6, 'extended-forecast'));
|
registerDisplay(new ExtendedForecast(7, 'extended-forecast'));
|
||||||
|
|
138
server/scripts/modules/hourly-graph.mjs
Normal file
138
server/scripts/modules/hourly-graph.mjs
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
// hourly forecast list
|
||||||
|
|
||||||
|
import STATUS from './status.mjs';
|
||||||
|
import getHourlyData from './hourly.mjs';
|
||||||
|
import WeatherDisplay from './weatherdisplay.mjs';
|
||||||
|
import { registerDisplay } from './navigation.mjs';
|
||||||
|
import { DateTime } from '../vendor/auto/luxon.mjs';
|
||||||
|
|
||||||
|
class HourlyGraph extends WeatherDisplay {
|
||||||
|
constructor(navId, elemId, defaultActive) {
|
||||||
|
// special height and width for scrolling
|
||||||
|
super(navId, elemId, 'Hourly Graph', defaultActive);
|
||||||
|
|
||||||
|
// move the top right data into the correct location on load
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
this.moveHeader();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
moveHeader() {
|
||||||
|
// get the header
|
||||||
|
const header = this.fillTemplate('top-right', {});
|
||||||
|
// place the header
|
||||||
|
this.elem.querySelector('.header .right').append(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getData() {
|
||||||
|
if (!super.getData()) return;
|
||||||
|
|
||||||
|
const data = await getHourlyData();
|
||||||
|
|
||||||
|
// get interesting data
|
||||||
|
const temperature = data.map((d) => d.temperature);
|
||||||
|
const probabilityOfPrecipitation = data.map((d) => d.probabilityOfPrecipitation);
|
||||||
|
const skyCover = data.map((d) => d.skyCover);
|
||||||
|
|
||||||
|
this.data = {
|
||||||
|
skyCover, temperature, probabilityOfPrecipitation,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setStatus(STATUS.loaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawCanvas() {
|
||||||
|
if (!this.canvas) this.canvas = this.elem.querySelector('.chart canvas');
|
||||||
|
|
||||||
|
// get available space
|
||||||
|
const boundingRect = this.canvas.getBoundingClientRect();
|
||||||
|
const availableWidth = boundingRect.width;
|
||||||
|
const availableHeight = boundingRect.height;
|
||||||
|
|
||||||
|
this.canvas.width = availableWidth;
|
||||||
|
this.canvas.height = availableHeight;
|
||||||
|
|
||||||
|
// get context
|
||||||
|
const ctx = this.canvas.getContext('2d');
|
||||||
|
ctx.imageSmoothingEnabled = false;
|
||||||
|
|
||||||
|
// calculate time scale
|
||||||
|
const timeScale = calcScale(0, 5, this.data.temperature.length - 1, availableWidth);
|
||||||
|
const startTime = DateTime.now().startOf('hour');
|
||||||
|
document.querySelector('.x-axis .l-1').innerHTML = formatTime(startTime);
|
||||||
|
document.querySelector('.x-axis .l-2').innerHTML = formatTime(startTime.plus({ hour: 6 }));
|
||||||
|
document.querySelector('.x-axis .l-3').innerHTML = formatTime(startTime.plus({ hour: 12 }));
|
||||||
|
document.querySelector('.x-axis .l-4').innerHTML = formatTime(startTime.plus({ hour: 18 }));
|
||||||
|
document.querySelector('.x-axis .l-5').innerHTML = formatTime(startTime.plus({ hour: 24 }));
|
||||||
|
|
||||||
|
// order is important last line drawn is on top
|
||||||
|
// clouds
|
||||||
|
const percentScale = calcScale(0, availableHeight - 10, 100, 10);
|
||||||
|
const cloud = createPath(this.data.skyCover, timeScale, percentScale);
|
||||||
|
drawPath(cloud, ctx, {
|
||||||
|
strokeStyle: 'lightgrey',
|
||||||
|
lineWidth: 3,
|
||||||
|
});
|
||||||
|
|
||||||
|
// precip
|
||||||
|
const precip = createPath(this.data.probabilityOfPrecipitation, timeScale, percentScale);
|
||||||
|
drawPath(precip, ctx, {
|
||||||
|
strokeStyle: 'aqua',
|
||||||
|
lineWidth: 3,
|
||||||
|
});
|
||||||
|
|
||||||
|
// temperature
|
||||||
|
const minTemp = Math.min(...this.data.temperature);
|
||||||
|
const maxTemp = Math.max(...this.data.temperature);
|
||||||
|
const midTemp = Math.round((minTemp + maxTemp) / 2);
|
||||||
|
const tempScale = calcScale(minTemp, availableHeight - 10, maxTemp, 10);
|
||||||
|
const tempPath = createPath(this.data.temperature, timeScale, tempScale);
|
||||||
|
drawPath(tempPath, ctx, {
|
||||||
|
strokeStyle: 'red',
|
||||||
|
lineWidth: 3,
|
||||||
|
});
|
||||||
|
|
||||||
|
// temperature axis labels
|
||||||
|
this.elem.querySelector('.y-axis .l-1').innerHTML = maxTemp;
|
||||||
|
this.elem.querySelector('.y-axis .l-2').innerHTML = midTemp;
|
||||||
|
this.elem.querySelector('.y-axis .l-3').innerHTML = minTemp;
|
||||||
|
|
||||||
|
super.drawCanvas();
|
||||||
|
this.finishDraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a scaling function from two points
|
||||||
|
const calcScale = (x1, y1, x2, y2) => {
|
||||||
|
const m = (y2 - y1) / (x2 - x1);
|
||||||
|
const b = y1 - m * x1;
|
||||||
|
return (x) => m * x + b;
|
||||||
|
};
|
||||||
|
|
||||||
|
// create a path as an array of [x,y]
|
||||||
|
const createPath = (data, xScale, yScale) => data.map((d, i) => [xScale(i), yScale(d)]);
|
||||||
|
|
||||||
|
// draw a path with shadow
|
||||||
|
const drawPath = (path, ctx, options) => {
|
||||||
|
// first shadow
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.strokeStyle = 'black';
|
||||||
|
ctx.lineWidth = (options?.lineWidth ?? 2) + 2;
|
||||||
|
ctx.moveTo(path[0][0], path[0][1]);
|
||||||
|
path.slice(1).forEach((point) => ctx.lineTo(point[0], point[1] + 2));
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// then colored line
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.strokeStyle = options?.strokeStyle ?? 'red';
|
||||||
|
ctx.lineWidth = (options?.lineWidth ?? 2);
|
||||||
|
ctx.moveTo(path[0][0], path[0][1]);
|
||||||
|
path.slice(1).forEach((point) => ctx.lineTo(point[0], point[1]));
|
||||||
|
ctx.stroke();
|
||||||
|
};
|
||||||
|
|
||||||
|
// format as 1p, 12a, etc.
|
||||||
|
const formatTime = (time) => time.toFormat('ha').slice(0, -1);
|
||||||
|
|
||||||
|
// register display
|
||||||
|
registerDisplay(new HourlyGraph(3, 'hourly-graph'));
|
|
@ -29,7 +29,7 @@ class Hourly extends WeatherDisplay {
|
||||||
|
|
||||||
async getData(weatherParameters) {
|
async getData(weatherParameters) {
|
||||||
// super checks for enabled
|
// super checks for enabled
|
||||||
if (!super.getData(weatherParameters)) return;
|
const superResponse = super.getData(weatherParameters);
|
||||||
let forecast;
|
let forecast;
|
||||||
try {
|
try {
|
||||||
// get the forecast
|
// get the forecast
|
||||||
|
@ -43,6 +43,9 @@ class Hourly extends WeatherDisplay {
|
||||||
|
|
||||||
this.data = await Hourly.parseForecast(forecast.properties);
|
this.data = await Hourly.parseForecast(forecast.properties);
|
||||||
|
|
||||||
|
this.getDataCallback();
|
||||||
|
if (!superResponse) return;
|
||||||
|
|
||||||
this.setStatus(STATUS.loaded);
|
this.setStatus(STATUS.loaded);
|
||||||
this.drawLongCanvas();
|
this.drawLongCanvas();
|
||||||
}
|
}
|
||||||
|
@ -66,6 +69,8 @@ class Hourly extends WeatherDisplay {
|
||||||
apparentTemperature: celsiusToFahrenheit(apparentTemperature[idx]),
|
apparentTemperature: celsiusToFahrenheit(apparentTemperature[idx]),
|
||||||
windSpeed: kilometersToMiles(windSpeed[idx]),
|
windSpeed: kilometersToMiles(windSpeed[idx]),
|
||||||
windDirection: directionToNSEW(windDirection[idx]),
|
windDirection: directionToNSEW(windDirection[idx]),
|
||||||
|
probabilityOfPrecipitation: probabilityOfPrecipitation[idx],
|
||||||
|
skyCover: skyCover[idx],
|
||||||
icon: icons[idx],
|
icon: icons[idx],
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -184,7 +189,20 @@ class Hourly extends WeatherDisplay {
|
||||||
return dayName;
|
return dayName;
|
||||||
}, '');
|
}, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make data available outside this class
|
||||||
|
// promise allows for data to be requested before it is available
|
||||||
|
async getCurrentData() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (this.data) resolve(this.data);
|
||||||
|
// data not available, put it into the data callback queue
|
||||||
|
this.getDataCallbacks.push(() => resolve(this.data));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// register display
|
// register display
|
||||||
registerDisplay(new Hourly(2, 'hourly'));
|
const display = new Hourly(2, 'hourly', false);
|
||||||
|
registerDisplay(display);
|
||||||
|
|
||||||
|
export default display.getCurrentData.bind(display);
|
||||||
|
|
|
@ -93,4 +93,4 @@ class LocalForecast extends WeatherDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
// register display
|
// register display
|
||||||
registerDisplay(new LocalForecast(5, 'local-forecast'));
|
registerDisplay(new LocalForecast(6, 'local-forecast'));
|
||||||
|
|
|
@ -281,7 +281,7 @@ const generateCheckboxes = () => {
|
||||||
|
|
||||||
if (!availableDisplays) return;
|
if (!availableDisplays) return;
|
||||||
// generate checkboxes
|
// generate checkboxes
|
||||||
const checkboxes = displays.map((d) => d.generateCheckbox()).filter((d) => d);
|
const checkboxes = displays.map((d) => d.generateCheckbox(d.defaultEnabled)).filter((d) => d);
|
||||||
|
|
||||||
// write to page
|
// write to page
|
||||||
availableDisplays.innerHTML = '';
|
availableDisplays.innerHTML = '';
|
||||||
|
|
|
@ -402,4 +402,4 @@ class Radar extends WeatherDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
// register display
|
// register display
|
||||||
registerDisplay(new Radar(8, 'radar'));
|
registerDisplay(new Radar(9, 'radar'));
|
||||||
|
|
|
@ -389,4 +389,4 @@ class RegionalForecast extends WeatherDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
// register display
|
// register display
|
||||||
registerDisplay(new RegionalForecast(4, 'regional-forecast'));
|
registerDisplay(new RegionalForecast(5, 'regional-forecast'));
|
||||||
|
|
|
@ -160,4 +160,4 @@ class TravelForecast extends WeatherDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
// register display, not active by default
|
// register display, not active by default
|
||||||
registerDisplay(new TravelForecast(3, 'travel', false));
|
registerDisplay(new TravelForecast(4, 'travel', false));
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
150
server/styles/scss/_hourly-graph.scss
Normal file
150
server/styles/scss/_hourly-graph.scss
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
@use 'shared/_colors'as c;
|
||||||
|
@use 'shared/_utils'as u;
|
||||||
|
|
||||||
|
#hourly-graph-html {
|
||||||
|
background-image: url(../images/BackGround1_1_Chart.png);
|
||||||
|
|
||||||
|
.header {
|
||||||
|
.right {
|
||||||
|
position: absolute;
|
||||||
|
top: 35px;
|
||||||
|
right: 60px;
|
||||||
|
width: 360px;
|
||||||
|
font-family: 'Star4000 Small';
|
||||||
|
font-size: 32px;
|
||||||
|
@include u.text-shadow();
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
div {
|
||||||
|
margin-top: -18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.temperature {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cloud {
|
||||||
|
color: lightgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rain {
|
||||||
|
color: aqua;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.weather-display .main.hourly-graph {
|
||||||
|
|
||||||
|
&.main {
|
||||||
|
>div {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-family: 'Star4000 Small';
|
||||||
|
font-size: 24pt;
|
||||||
|
color: c.$column-header-text;
|
||||||
|
@include u.text-shadow();
|
||||||
|
margin-top: -15px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.x-axis {
|
||||||
|
bottom: 0px;
|
||||||
|
left: 0px;
|
||||||
|
width: 640px;
|
||||||
|
height: 20px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
text-align: center;
|
||||||
|
width: 50px;
|
||||||
|
|
||||||
|
&.l-1 {
|
||||||
|
left: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.l-2 {
|
||||||
|
left: 158px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.l-3 {
|
||||||
|
left: 291px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.l-4 {
|
||||||
|
left: 424px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.l-5 {
|
||||||
|
left: 557px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
top: 0px;
|
||||||
|
left: 50px;
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
width: 532px;
|
||||||
|
height: 285px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.y-axis {
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
width: 50px;
|
||||||
|
height: 285px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
text-align: right;
|
||||||
|
right: 0px;
|
||||||
|
|
||||||
|
&.l-1 {
|
||||||
|
top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.l-2 {
|
||||||
|
top: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.l-3 {
|
||||||
|
bottom: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-headers {
|
||||||
|
background-color: c.$column-header;
|
||||||
|
height: 20px;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-headers {
|
||||||
|
position: sticky;
|
||||||
|
top: 0px;
|
||||||
|
z-index: 5;
|
||||||
|
|
||||||
|
|
||||||
|
.temp {
|
||||||
|
left: 355px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.like {
|
||||||
|
left: 435px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wind {
|
||||||
|
left: 535px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -269,12 +269,6 @@ jsgif {
|
||||||
font-size: 18pt;
|
font-size: 18pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
#container canvas {
|
|
||||||
/* position: absolute; */
|
|
||||||
width: 100%;
|
|
||||||
/* max-width: 640px; */
|
|
||||||
}
|
|
||||||
|
|
||||||
.heading {
|
.heading {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
@import 'current-weather';
|
@import 'current-weather';
|
||||||
@import 'extended-forecast';
|
@import 'extended-forecast';
|
||||||
@import 'hourly';
|
@import 'hourly';
|
||||||
|
@import 'hourly-graph';
|
||||||
@import 'travel';
|
@import 'travel';
|
||||||
@import 'latest-observations';
|
@import 'latest-observations';
|
||||||
@import 'local-forecast';
|
@import 'local-forecast';
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
<script type="module" src="scripts/modules/almanac.mjs"></script>
|
<script type="module" src="scripts/modules/almanac.mjs"></script>
|
||||||
<script type="module" src="scripts/modules/icons.mjs"></script>
|
<script type="module" src="scripts/modules/icons.mjs"></script>
|
||||||
<script type="module" src="scripts/modules/extendedforecast.mjs"></script>
|
<script type="module" src="scripts/modules/extendedforecast.mjs"></script>
|
||||||
|
<script type="module" src="scripts/modules/hourly-graph.mjs"></script>
|
||||||
<script type="module" src="scripts/modules/hourly.mjs"></script>
|
<script type="module" src="scripts/modules/hourly.mjs"></script>
|
||||||
<script type="module" src="scripts/modules/latestobservations.mjs"></script>
|
<script type="module" src="scripts/modules/latestobservations.mjs"></script>
|
||||||
<script type="module" src="scripts/modules/localforecast.mjs"></script>
|
<script type="module" src="scripts/modules/localforecast.mjs"></script>
|
||||||
|
@ -90,6 +91,9 @@
|
||||||
<div id="hourly-html" class="weather-display">
|
<div id="hourly-html" class="weather-display">
|
||||||
<%- include('partials/hourly.ejs') %>
|
<%- include('partials/hourly.ejs') %>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="hourly-graph-html" class="weather-display">
|
||||||
|
<%- include('partials/hourly-graph.ejs') %>
|
||||||
|
</div>
|
||||||
<div id="travel-html" class="weather-display">
|
<div id="travel-html" class="weather-display">
|
||||||
<%- include('partials/travel.ejs') %>
|
<%- include('partials/travel.ejs') %>
|
||||||
</div>
|
</div>
|
||||||
|
@ -126,7 +130,7 @@
|
||||||
<img id="NavigateRefresh" class="navButton" src="images/nav/ic_refresh_white_24dp_1x.png" title="Refresh" />
|
<img id="NavigateRefresh" class="navButton" src="images/nav/ic_refresh_white_24dp_1x.png" title="Refresh" />
|
||||||
</div>
|
</div>
|
||||||
<div id="divTwcBottomRight">
|
<div id="divTwcBottomRight">
|
||||||
<img id="ToggleFullScreen" class="navButton" src="images/nav/ic_fullscreen_exit_white_24dp_1x.png" title="Enter Fullscreen" />
|
<img id="ToggleFullScreen" class="navButton" src="images/nav/ic_fullscreen_white_24dp_1x.png" title="Enter Fullscreen" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
<% if (locals?.hasTime) { %>
|
<% if (locals?.hasTime) { %>
|
||||||
<div class="date-time date"></div>
|
<div class="date-time date"></div>
|
||||||
<div class="date-time time"></div>
|
<div class="date-time time"></div>
|
||||||
|
<% } else if (!locals?.noaaLogo) { %>
|
||||||
|
<div class="right"></div>
|
||||||
<% } %>
|
<% } %>
|
||||||
<% if (locals?.noaaLogo) { %>
|
<% if (locals?.noaaLogo) { %>
|
||||||
<div class="noaa-logo">
|
<div class="noaa-logo">
|
||||||
|
|
24
views/partials/hourly-graph.ejs
Normal file
24
views/partials/hourly-graph.ejs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<%- include('header.ejs', {title: 'Hourly Graph' , hasTime: false }) %>
|
||||||
|
<div class="main has-scroll hourly-graph">
|
||||||
|
<div class="top-right template ">
|
||||||
|
<div class="temperature">Temperature</div>
|
||||||
|
<div class="cloud">Cloud %</div>
|
||||||
|
<div class="rain">Precip %</div>
|
||||||
|
</div>
|
||||||
|
<div class="y-axis">
|
||||||
|
<div class="label l-1">75</div>
|
||||||
|
<div class="label l-2">65</div>
|
||||||
|
<div class="label l-3">55</div>
|
||||||
|
</div>
|
||||||
|
<div class="chart">
|
||||||
|
<canvas id="chart-area"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="x-axis">
|
||||||
|
<div class="label l-1">12a</div>
|
||||||
|
<div class="label l-2">6a</div>
|
||||||
|
<div class="label l-3">12p</div>
|
||||||
|
<div class="label l-4">6p</div>
|
||||||
|
<div class="label l-5">12a</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<%- include('scroll.ejs') %>
|
Loading…
Reference in a new issue