ソーラー発電&Arduino測定の気象データをChart.jsでグラフ化⑤表示調整
目次
前回
今回はちょこちょことお父ちゃんから依頼のあった表示の調整を行いました。
ソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
<!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"> </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://cdn.jsdelivr.net/npm/chart.js/dist/chart.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script> <script> var myChart; var mode = 'airPressure'; // 初期表示:気圧 var weatherData = {}; weatherData.label = { 'batteryVoltage': 'バッテリー電圧', 'solarVoltage': 'ソーラー電圧', 'airPressure': '気圧', 'temperature': '気温', 'humidity': '湿度' }; weatherData.time = []; weatherData.batteryVoltage = []; weatherData.solarVoltage = []; weatherData.airPressure = []; weatherData.temperature = []; weatherData.humidity = []; weatherData.data = []; // データ取得 const str = "<?php echo preg_replace('/\n/',',',file_get_contents('/path/to/file')); ?>"; const str_array = str.split(','); 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.time[i] = _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]; } //drawMyChart function drawMyChart(){ for (var i = 0; i < weatherData.time.length; i++) { weatherData.data[i] = { x: new Date( weatherData.time[i] ), y: weatherData[mode][i] } } const ctx = document.getElementById('myChart').getContext('2d'); if (myChart) { myChart.destroy(); } // フォントサイズ Chart.defaults.font.size = 16; // canvas 背景色 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(); } }; myChart = new Chart(ctx, { type: 'line', data: { datasets: [{ label: weatherData.label[mode], data: weatherData.data, fill: false, borderColor: 'rgb(75, 192, 192)', tension: 0.1 }] }, options: { maintainAspectRatio: false, scales: { x: { type: 'time', time: { unit: 'day', }, min: weatherData.min, max: weatherData.max } } }, plugins: [plugin] }); } drawMyChart(); // グラフ切替 $('.button-type button').click(function(event) { if( !$(this).hasClass('active') ) { $('.button-type button').removeClass('active'); $(this).addClass('active'); mode = $(this).data('mode'); drawMyChart() } }); // datepicker $('.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()) { var type = $(this).attr('id') == 'date-start' ? 'min' : 'max'; weatherData[type] = ''; drawMyChart(); } }); </script> </body> </html> |
①フォントサイズ
<ラベルのフォントサイズが小さい
1 |
Chart.defaults.font.size = 16; |
②グラフの背景色
1 2 3 4 5 6 7 8 9 10 11 |
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(); } }; |
1 |
plugins: [plugin] |
③グラフのサイズ
これは私も気になっていた・・
グラフの下が画面からはみ出てスクロールが必要な状態になっている。
(↑下がはみ出て見切れている)
responsive の設定
そもそもcanvasサイズを指定しているのに反映されないのが不思議だったのですが、
1 |
<canvas id="myChart" width="800" height="400"></canvas> |
Chart.js はデフォルトでレスポンシブのオプションがtrueになっているからでした。
これを false にすると、指定したサイズで表示されるようになりました。
1 |
responsive: false |
maintainAspectRatio
maintainAspectRatio という設定もあり、
こちらはレスポンシブの時に元のアスペクト比を維持する設定で、
デフォルトで true になっているようでした。
最初 canvas サイズを400×400 で設定していたから、
正方形になって伸びてしまっていたようです。
maintainAspectRatio を false に設定することで、
横幅がレスポンシブ対応になり、高さが固定表示になるようでした。
1 |
maintainAspectRatio: false, |
canvas は div で囲む
上記を設定する際は、canvas を div 等で囲む必要がありました!
1 2 3 |
<div class="chart-container" style="position: relative; height:80vh; width:100%"> <canvas id="myChart"></canvas> </div> |
囲んでいないと、
グラフの縦幅がどんどん伸びていく怪奇現象に見舞われました🥲
親コンテナ注意点
いくつか注意点があるようです。
- サイズはcanvas自体ではなく親コンテナで指定する
- 親コンテナには position:relative を指定
- コンテナには canvas のみがある状態(他の要素が入っていてはだめ)
↓引用↓
キャンバスサイズ変更を、
CANVAS
要素から直接の検出することはできません。 キャンバスレンダリングサイズとディスプレイサイズを更新するために、Chart.jsでは親コンテナを使用します。ただしこの方法では、コンテナが相対配置(position:relative)されていることと、チャートキャンバスのみを含むことが必要です。これにより、コンテナサイズの相対値を設定することでレスポンシブ機能が実現できます。
とりあえず今回は height:80vh; width:100%; にすることで
だいたい画面いっぱいに表示することができました。
ちゃんと画面に収まるようになり、だいぶ見やすくなりました!
これでひとまずグラフ化、完了🙌