<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>ベランダ気象データ</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<link rel="stylesheet" href="https://code.jquery.com/ui/1.13.0/themes/base/jquery-ui.css">
</head>
<body>
<nav class="navbar navbar-light bg-light mb-4">
<div class="container">
<span class="navbar-brand mb-0 h1">ベランダ気象データ</span>
</div>
</nav>
<div class="container">
<div class="button-type border-bottom pb-2 mb-2">
種別
<button type="button" class="btn btn-outline-primary active" data-mode="airPressure">気圧</button>
<button type="button" class="btn btn-outline-primary" data-mode="temperature">気温</button>
<button type="button" class="btn btn-outline-primary" data-mode="humidity">湿度</button>
<button type="button" class="btn btn-outline-primary" data-mode="batteryVoltage">バッテリー電圧</button>
<button type="button" class="btn btn-outline-primary" data-mode="solarVoltage">ソーラー電圧</button>
</div>
<div class="period">
期間 <input type="text" class="form-control d-inline-block datepicker" style="width:150px;" id="date-start">
〜 <input type="text" class="form-control d-inline-block datepicker" style="width:150px;" id="date-end">
<button type="button" class="btn btn-outline-primary" data-mode="24h">24時間</button>
<button type="button" class="btn btn-outline-primary" data-mode="1w">1週間</button>
<button type="button" class="btn btn-outline-primary active" data-mode="1m">1ヶ月</button>
<button type="button" class="btn btn-outline-primary" data-mode="6m">半年</button>
<button type="button" class="btn btn-outline-primary" data-mode="1y">1年</button>
<button type="button" class="btn btn-outline-primary" data-mode="all">全期間</button>
</div>
<div class="chart-container" style="position: relative; height:80vh; width:100%">
<canvas id="myChart"></canvas>
</div>
</div>
<script
src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"></script>
<script src="https://code.jquery.com/ui/1.13.0/jquery-ui.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js" integrity="sha512-ElRFoEQdI5Ht6kZvyzXhYG9NqjtkmlkfYk0wr6wHxU9JEHakS7UJZNeml5ALk+8IKlU6jDgMabC3vkumRokgJA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<?php
// ログファイル一覧取得
chdir("./logs");
$array = glob("*");
$json_array = json_encode($array);
?>
<script>
var logFiles = <?php echo $json_array; ?>
var myChart;
var weatherData = {};
weatherData.unit = 'day'; // 初期単位:日
weatherData.mode = 'airPressure'; // 初期表示:気圧
weatherData.label = {
'batteryVoltage': 'バッテリー電圧',
'solarVoltage': 'ソーラー電圧',
'airPressure': '気圧',
'temperature': '気温',
'humidity': '湿度'
};
weatherData.date = [];
weatherData.time = [];
weatherData.batteryVoltage = [];
weatherData.solarVoltage = [];
weatherData.airPressure = [];
weatherData.temperature = [];
weatherData.humidity = [];
weatherData.hourly = [];
// Chart 設定
Chart.defaults.font.size = 16;
const plugin = {
id: 'custom_canvas_background_color',
beforeDraw: (chart) => {
const ctx = chart.canvas.getContext('2d');
ctx.save();
ctx.globalCompositeOperation = 'destination-over';
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, chart.width, chart.height);
ctx.restore();
}
};
//drawMyChart
function drawMyChart(){
var myChartData = [];
var period = weatherData.max - weatherData.min;
if ( period <= 86400000 ) { // 24時間
weatherData.unit = 'hour';
} else if ( period <= 5184000000 ) { // 60日
weatherData.unit = 'day';
} else {
weatherData.unit = 'month';
}
if ( weatherData.unit == 'month' ) {
for (var i = 0; i < weatherData.hourly.length; i++) {
if( weatherData.hourly[i].time >= weatherData.min && weatherData.hourly[i].time <= weatherData.max ) {
myChartData.push({
x: new Date( weatherData.hourly[i].time ),
y: weatherData[weatherData.mode][weatherData.hourly[i].index]
});
}
}
} else {
for (var i = 0; i < weatherData.time.length; i++) {
if( weatherData.time[i] >= weatherData.min && weatherData.time[i] <= weatherData.max ) {
myChartData.push({
x: new Date( weatherData.time[i] ),
y: weatherData[weatherData.mode][i]
});
}
}
}
const ctx = document.getElementById('myChart').getContext('2d');
if (myChart) {
myChart.destroy();
}
myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: weatherData.label[weatherData.mode],
data: myChartData,
fill: false,
borderColor: 'rgb(75, 192, 192)',
tension: 0.1
}]
},
options: {
maintainAspectRatio: false,
scales: {
x: {
type: 'time',
time: {
unit: weatherData.unit,
}
}
}
},
plugins: [plugin]
});
}
// クリックイベント
// グラフ切替
$('.button-type button').click(function(event) {
if( !$(this).hasClass('active') ) {
$('.button-type button').removeClass('active');
$(this).addClass('active');
weatherData.mode = $(this).data('mode');
drawMyChart()
}
});
// 日付範囲
$('.datepicker').datepicker({
dateFormat: 'yy/mm/dd',
onSelect: function(dateText, inst){
var type = $(this).attr('id') == 'date-start' ? 'min' : 'max';
weatherData[type] = new Date(dateText);
drawMyChart();
}
});
$('.period input').on('input',function(event) {
// 空の場合
if (!$(this).val()) {
if ( $(this).attr('id') == 'date-start' ) {
weatherData.min = weatherData.time[0];
} else {
weatherData.max = new Date();
}
drawMyChart();
}
});
// 期間ボタン
$('.period .btn').click(function(event) {
if( !$(this).hasClass('active') ) {
$('.period .btn').removeClass('active');
$(this).addClass('active');
var dt = new Date();
var minDate = '';
switch ($(this).data('mode')) {
case '24h':
weatherData.min = dt.setHours(dt.getHours() - 24);
break;
case '1w':
weatherData.min = dt.setDate(dt.getDate() - 7);
break;
case '1m':
weatherData.min = dt.setMonth(dt.getMonth() - 1);
break;
case '6m':
weatherData.min = dt.setMonth(dt.getMonth() - 6);
break;
case '1y':
weatherData.min = dt.setYear(dt.getYear() - 1);
break;
case 'all':
weatherData.min = weatherData.time[0];
break;
}
weatherData.min = new Date(weatherData.min);
weatherData.max = new Date();
drawMyChart();
}
});
// ログファイル取得
var jqXHRList = [];
for (var i = 0; i < logFiles.length; i++) {
jqXHRList.push($.ajax({
type: 'GET',
contentType: 'txt',
url: './logs/' + logFiles[i],
}));
}
$.when.apply($, jqXHRList).done(function () {
var json = [];
var statuses = [];
var jqXHRResultList = [];
var str = '';
for (var i = 0; i < arguments.length; i++) {
var result = arguments[i];
json.push(result[0]);
statuses.push(result[1]);
jqXHRResultList.push(result[3]);
str += result[0].replace(/\n/gm,',');
}
const str_array = str.split(',');
var comparisonTime = new Date();
for (var i=0; i<str_array.length; i++) {
var _str = str_array[i].replace(/ /,',').replace(/\t/g,',').replace(/ /g,'');
var _data = _str.split(',');
weatherData.date[i] = new Date(_data[0]);
weatherData.time[i] = new Date(_data[0] + ' ' + _data[1]);
weatherData.batteryVoltage[i] = _data[2];
weatherData.solarVoltage[i] = _data[3];
weatherData.airPressure[i] = _data[4];
weatherData.temperature[i] = _data[5];
weatherData.humidity[i] = _data[6];
// 時間ごとのデータ
if ( comparisonTime.getHours() != weatherData.time[i].getHours() ) {
comparisonTime = weatherData.time[i];
weatherData.hourly.push({
time: weatherData.time[i],
index: i
});
}
}
// 初期値
var dt = new Date();
weatherData.min = new Date(dt.setMonth(dt.getMonth() - 1));
weatherData.max = new Date();
drawMyChart();
}).fail(function (ex) {
console.log('error');
});
</script>
</body>
</html>