function draw_graph(id, title, data, date, limit, range, div, color_table, checkbox) { // グラフ描画 var canvas = document.getElementById(id); const x_min = 95; const x_max = canvas.width - 90; const y_min = 70; const y_max = canvas.height - 50; const min = range[0]; const max = range[1]; var context = init_graph(canvas); var div2 = div; if(div > 168) { div2 /= 24; } // 昼夜で色を分割 draw_gray(context, date, div, x_min, x_max, y_min, y_max); // 軸描画 draw_axis(context, x_min, x_max, y_min, y_max); // グリッド出力 draw_grid(context, min, max, div2 + 1, x_min, x_max, y_min, y_max); // 折れ線グラフの描画 if(!is_array(data)) { draw_data(data, context, color_table, min, max, x_min, x_max, y_min, y_max); } else { for(var i = 0; i < data.length; i++) { if(checkbox[i]) { var color = color_table[i]; draw_data(data[i], context, color, min, max, x_min, x_max, y_min, y_max); } } } // グラフ描画領域から飛び出した部分の消去 context.clearRect(0, 0, canvas.width - 30, 45); context.clearRect(0, y_max + 1, canvas.width - 30, canvas.height); // x軸ラベル出力 if(div <= 168) { draw_xaxis_time(canvas, context, date, div2, x_min, x_max, y_max); } else { draw_xaxis_day(canvas, context, date, div2, x_min, x_max, y_max); } // y軸ラベル出力 draw_yaxis(context, min, max, x_min, y_min, y_max); // y軸表示範囲スライダーの目盛り描画 draw_range_line(context, limit, range, x_min, y_min, y_max); draw_vertical_slider_tick(context, limit, y_min); // 表示期間スライダーの目盛り描画 draw_horizontal_slider_tick(context); // グラフタイトルの描画 draw_text(context, title, 5, 20); } function make_data_set(data, term, column, date, offset, step) { // データセットの作成 var data_set = new Array(term * (60 / step) + 1); date.setHours(date.getHours() + offset); dt = new Date(date); if(term > 168) { var diff = 24 - dt.getHours(); dt.setHours(dt.getHours() + diff); } st_buf = data.length - 1; for(var i = data_set.length - 1; i >= 0; i--) { data_set[i] = extract_data_column(data, column, dt, st_buf); dt.setMinutes(dt.getMinutes() - step); } st_buf = 0; return data_set; } function init_graph(canvas) { // グラフの初期化 var context = canvas.getContext('2d'); context.clearRect(0, 0, canvas.width, canvas.height); return context; } function draw_axis(context, x_min, x_max, y_min, y_max) { // 軸描画 context.strokeStyle = "#000000"; context.beginPath(); // 横軸の描画 context.moveTo(x_min, y_max); context.lineTo(x_max + 20, y_max); // 縦軸の描画 context.moveTo(x_min, y_min - 25); context.lineTo(x_min, y_max); context.closePath(); context.stroke(); } function draw_xaxis_time(canvas, context, dt, div, x_min, x_max, y_max) { // x軸ラベル出力(時刻版) var date = new Date(dt); date.setHours(date.getHours() - div); var hour = date.getHours(); context.strokeStyle = "#000000"; context.font = "9pt Arial"; context.beginPath(); for(var i = 0; i <= div / 2; i++) { if(i == 0) { context.fillText((date.getMonth() + 1) + "月" + (date.getDate()) + "日", ((x_min - 35) + i * (2 * (x_max - x_min) / div)), canvas.height - 5); } else if(hour == 0) { if(date.getDate() == 1) { context.fillText((date.getMonth() + 1) + "月" + (date.getDate()) + "日", ((x_min - 20) + i * (2 * (x_max - x_min) / div)), canvas.height - 5); } else { context.fillText(date.getDate() + "日", ((x_min - 10) + i * (2 * (x_max - x_min) / div)), canvas.height - 5); } } context.fillText(hour + "時", ((x_min - 10) + i * ( 2 * (x_max - x_min) / div)), canvas.height - 35); context.moveTo((x_min + i * (2 * ((x_max - x_min) / div))), y_max - 2); context.lineTo((x_min + i * (2 * ((x_max - x_min) / div))), y_max + 2); date.setHours(date.getHours() + 2); hour = date.getHours(); } date = new Date(dt); date.setHours((date.getHours() + 1) - div); hour = date.getHours(); for(var i = 0; i < div / 2; i++) { if(hour == 0) { if(date.getDate() == 1) { context.fillText((date.getMonth() + 1) + "月" + date.getDate() + "日", ((x_min - 20) + ((x_max - x_min) / div) + i * (2 * (x_max - x_min) / div)), canvas.height - 5); } else { context.fillText(date.getDate() + "日", ((x_min - 10) + ((x_max - x_min) / div) + i * (2 * (x_max - x_min) / div)), canvas.height - 5); } } context.fillText(hour + "時", ((x_min - 10) + ((x_max - x_min) / div) + i * (2 * ((x_max - x_min) / div))), canvas.height - 20); context.moveTo(x_min + ((x_max - x_min) / div) + i * (2 * ((x_max - x_min) / div)), y_max - 2); context.lineTo(x_min + ((x_max - x_min) / div) + i * (2 * ((x_max - x_min) / div)), y_max + 2); date.setHours(date.getHours() + 2); hour = date.getHours(); } context.closePath(); context.stroke(); } function draw_xaxis_day(canvas, context, date, div, x_min, x_max, y_max) { // x軸ラベル出力(日付版) var dt = new Date(date); dt.setDate(dt.getDate() - (div - 1)); var date2 = dt.getDate(); context.strokeStyle = "#000000"; context.font = "9pt Arial"; for(var i = 0; i <= div / 2; i++) { if(i == 0) { context.fillText((dt.getMonth() + 1) + "月", ((x_min - 10) + i * (2 * (x_max - x_min) / div)), canvas.height - 5); } else if(dt.getDate() == 1) { context.fillText((dt.getMonth() + 1) + "月", ((x_min - 10) + i * (2 * (x_max - x_min) / div)), canvas.height - 5); } context.fillText(date2 + "日", ((x_min - 10) + i * (2 * (x_max - x_min) / div)), canvas.height- 35); context.moveTo((x_min + i * (2 * ((x_max - x_min) / div))), y_max - 2); context.lineTo((x_min + i * (2 * ((x_max - x_min) / div))), y_max + 2); dt.setDate(dt.getDate() + 2); date2 = dt.getDate(); } dt = new Date(date); dt.setDate((dt.getDate() + 1) - (div - 1)); date2 = dt.getDate(); for(i = 0; i < div / 2; i++) { if(dt.getDate() == 1) { context.fillText((dt.getMonth() + 1) + "月", ((x_min - 10) + ((x_max - x_min) / div) + i * (2 * (x_max - x_min) / div)), canvas.height - 5); } context.fillText(date2 + "日", ((x_min - 10) + ((x_max - x_min) / div) + i * (2 * ((x_max - x_min) / div))), canvas.height - 20); context.moveTo(x_min + ((x_max - x_min) / div) + i * ( 2 * ((x_max - x_min) / div)), y_max - 2); context.lineTo(x_min + ((x_max - x_min) / div) + i * ( 2 * ((x_max - x_min) / div)), y_max + 2); dt.setDate(dt.getDate() + 2); date2 = dt.getDate(); } } function draw_gray(context, date, div, x_min, x_max, y_min, y_max) { // 昼夜で色を分割 var dt = new Date(date); if(div <= 48) { for(var i = div - 1; i >= 0; i--) { if(!(dt.getHours() > 6 && dt.getHours() <= 18)) { context.beginPath(); context.fillStyle = "#e6e6e6"; context.fillRect((x_min + i * ((x_max - x_min) / div)), y_min - 25, ((x_min + (i + 1) * ((x_max - x_min) / div)) - (x_min + i * ((x_max - x_min) / div))), y_max - (y_min - 25)); context.closePath(); context.stroke(); } dt.setHours(dt.getHours() - 1); } } else { for(var i = 0; i < div; i++) { if(!((i % 24) >= 6 && (i % 24) < 18)) { context.beginPath(); context.fillStyle = "#e6e6e6"; context.fillRect((x_min + i * ((x_max - x_min) / div)), y_min - 25, ((x_min + (i + 1) * ((x_max - x_min) / div)) - (x_min + i * ((x_max - x_min) / div))), y_max - (y_min - 25)); context.closePath(); context.stroke(); } } } context.fillStyle = "#000000"; } function draw_yaxis(context, min, max, x_min, y_min, y_max) { // y軸ラベル出力 context.beginPath(); context.strokeStyle = "#000000"; context.font = "9pt Arial"; var count = 0; for(var i = min; i < max; i += 5) { count++; } if(count < 3) { count = 0; for(var i = min; i < max; i++) count++; for(var i = min; i < 1 + max; i++) { var text = "" + i; text_w = context.measureText(text).width; context.fillText(text, (x_min - 5) - text_w, (y_max - ((y_max - y_min) / count) * (i - min)) + 5); } } else if(count >= 50) { count = 0; for(var i = min; i < max; i += 50) count++; for(var i = min / 50; i < 1 + max / 50; i++) { var text = "" + Math.round(i * 50); text_w = context.measureText(text).width; context.fillText(text, (x_min - 5) - text_w, (y_max - ((y_max - y_min) / count) * (i - min / 50)) + 5); } } else { for(var i = min / 5; i < 1 + max/5; i++) { var text = "" + Math.round(i * 5); text_w = context.measureText(text).width; context.fillText(text, (x_min - 5) - text_w, (y_max - ((y_max - y_min) / count) * (i - min / 5)) + 5); } } context.closePath(); context.stroke(); } function draw_data(data, context, color, min, max, x_min, x_max, y_min, y_max) { // 折れ線グラフの描画 const radius = 1.7 - (0.2 * (data.length - 1) / 24); var count = 0; for(var i = min; i < max; i++) count++; var pos1 = {x: -1, y: -1}; var pos2 = {x: -1, y: -1}; for(var i = 0; i < data.length; i++) { // データが欠測している場合は処理をスキップ if(data[i] == -1) continue; context.beginPath(); context.strokeStyle = color; pos1.x = x_min + i * ((x_max - x_min) / (data.length - 1)); pos1.y = y_max - ((y_max - y_min) / count) * (data[i] - min); if(pos2.x == -1 && pos2.y == -1) { context.moveTo(pos1.x, pos1.y); } else { context.moveTo(pos2.x, pos2.y); context.lineTo(pos1.x, pos1.y); context.stroke(); } if(radius >= 0.5) { draw_point(context, pos1.x, pos1.y, radius); } pos2.x = pos1.x; pos2.y = pos1.y; } context.closePath(); } function draw_point(context, x, y, radius) { // 点の描画 if(radius < 0) { radius = 0; } context.beginPath(); context.fillStyle="#000000"; context.arc(x, y, radius, 0, Math.PI * 2, true); context.closePath(); context.fill(); } function draw_grid(context, min, max, pt, x_min, x_max, y_min, y_max){ // グリッド出力 context.strokeStyle = "#afafaf"; var count = 0; for(var i = min; i < max; i+= 5) count++; for(var i = 0; i < pt; i++) { context.beginPath(); context.moveTo((x_min + i * (x_max - x_min) / (pt - 1)), y_min - 25); context.lineTo((x_min + i * (x_max - x_min) / (pt - 1)), y_max); context.closePath(); context.stroke(); } if(count < 3) { count = 0; for(var i = min; i < max; i++) count++; for(var i = 1 + min; i <= max; i++) { context.beginPath(); context.moveTo(x_min, (y_max - (((y_max - y_min) / count) * (i - min)))); context.lineTo(x_max + 20, (y_max - (((y_max - y_min) / count) * (i - min)))); context.closePath(); context.stroke(); } for(var i = 0.1 + min; i <= 1 + max; i += 0.1) { if(i % 1 != 0) { context.beginPath(); context.setLineDash([2,2]); context.moveTo(x_min, (y_max - (((y_max - y_min) / count) * (i - min)))); context.lineTo(x_max + 20, (y_max - (((y_max - y_min) / count) * (i - min)))); context.closePath(); context.stroke(); } } context.setLineDash([0,0]); } else if(count >= 50) { count = 0; for(var i = min; i < max; i += 50) count++; for(var i = 1 + min / 50; i < 1 + max / 50; i++) { context.beginPath(); context.moveTo(x_min, (y_max - (((y_max - y_min) / count) * (i - min / 50)))); context.lineTo(x_max + 20, (y_max - (((y_max - y_min) / count) * (i - min / 50)))); context.closePath(); context.stroke(); } for(var i = 0.2 + min / 50; i <= max / 50; i += 0.2) { if(i % 50 != 0) { context.beginPath(); context.setLineDash([2,2]); context.moveTo(x_min, (y_max - (((y_max - y_min) / count) * (i - min / 50)))); context.lineTo(x_max + 20, (y_max - (((y_max - y_min) / count) * (i - min / 50)))); context.closePath(); context.stroke(); } } context.setLineDash([0,0]); } else { for(var i = 1 + min / 5; i < 1 + max / 5; i++) { context.beginPath(); context.moveTo(x_min, (y_max - (((y_max - y_min) / count) * (i - min / 5)))); context.lineTo(x_max + 20, (y_max - (((y_max - y_min) / count) * (i - min / 5)))); context.closePath(); context.stroke(); } for(var i = 0.2 + min / 5; i <= max / 5; i += 0.2) { if(i % 5 != 0) { context.beginPath(); context.setLineDash([2,2]); context.moveTo(x_min, (y_max - (((y_max - y_min) / count) * (i - min / 5)))); context.lineTo(x_max + 20, (y_max - (((y_max - y_min) / count) * (i - min / 5)))); context.closePath(); context.stroke(); } } context.setLineDash([0,0]); } } function draw_text(context, text, x, y) { // テキストの描画 context.beginPath(); context.strokeStyle = "#000000"; context.font = "9pt Arial"; context.fillText(text, x, y); } function draw_horizontal_slider_tick(context){ const s_xmin = 170; const s_width = 340; const s_ymin = 25; context.beginPath(); context.strokeStyle = "#afafaf"; for(i = 0; i < tr_table.length; i++) { context.font = "9pt Arial"; var text = ""; var text_w = 0; if(i < 3) { text = ((tr_table[(tr_table.length - 1) - i] / 24) - 1) + "日間"; text_w = context.measureText(text).width; } else { text = tr_table[(tr_table.length - 1) - i] + "時間"; text_w = context.measureText(text).width; } draw_text(context, text, s_xmin + i * Math.round(s_width / (tr_table.length - 1)) - text_w / 2, s_ymin - 13); context.moveTo(s_xmin + i * Math.round(s_width / (tr_table.length - 1)), s_ymin - 10); context.lineTo(s_xmin + i * Math.round(s_width / (tr_table.length - 1)), s_ymin + 5); context.closePath(); context.stroke(); } context.strokeStyle = "#000000"; } function make_horizontal_slider() { // 表示期間変更スライダーの作成 const max = tr_table.length - 1; $(function() { for(var i = 0; i < item_list.length; i++) { var s_id = '#zoom' + i; $(s_id).slider({ min : 0, max : max, step : 1, value : max - time_range[i], slide : function(e, ui) { var sp = e.target.id.split("m"); var type = parseInt(sp[1]); var lv_id = '#zoom_lv' + type; change_text(lv_id, -1 * ui.value); }, change : function(e, ui) { var sp = e.target.id.split("m"); var canvas_id = 'past' + sp[1]; var id_num = parseInt(sp[1]); var lv_id = '#zoom_lv' + id_num; change_text(lv_id, -1 * ui.value); time_range_set(canvas_id, id_num, ui.value); }, create : function(e, ui) { var sp = e.target.id.split("m"); var canvas_id = 'past' + sp[1]; var id_num = parseInt(sp[1]); var lv_id = '#zoom_lv' + id_num; change_text(lv_id, -1 * $(this).slider('option', 'value')); time_range_set(canvas_id, id_num, $(this).slider('option', 'value')); } }); } }); } function time_range_set(id, num, value) { const title = item_list[num] + "の時間変化"; time_range[num] = (tr_table.length - 1) - value; switch(num) { case 0: data_set[0][0] = make_data_set(a_suishitsu[point], tr_table[time_range[0]], 2, load_date, 0, 30); data_set[0][1] = make_data_set(a_suishitsu[point], tr_table[time_range[0]], 6, load_date, 0, 30); data_set[0][2] = make_data_set(a_suishitsu[point], tr_table[time_range[0]], 13, load_date, 0, 30); data_set[0][3] = make_data_set(a_suishitsu[point], tr_table[time_range[0]], 10, load_date, 0, 30); data_set[0][1] = merge_dataset(data_set[0][1], data_set[0][3]); data_set[0].pop(); break; case 1: data_set[1][0] = make_data_set(a_suishitsu[point], tr_table[time_range[1]], 3, load_date, 0, 30); data_set[1][1] = make_data_set(a_suishitsu[point], tr_table[time_range[1]], 7, load_date, 0, 30); break; case 2: data_set[2][0] = make_data_set(a_suishitsu[point], tr_table[time_range[2]], 4, load_date, 0, 30); data_set[2][1] = make_data_set(a_suishitsu[point], tr_table[time_range[2]], 8, load_date, 0, 30); break; case 3: data_set[3][0] = make_data_set(a_suishitsu[point], tr_table[time_range[3]], 11, load_date, 0, 30); data_set[3][1] = make_data_set(a_suishitsu[point], tr_table[time_range[3]], 14, load_date, 0, 30); break; } draw_graph(id, title, data_set[num], load_date, limit[num], range[num], tr_table[time_range[num]], color_table[num], checkbox[num]); // Cookieの保存 var cookie = ""; for(var i = 0; i < time_range.length; i++) { cookie += time_range[i]; if(i != time_range.length - 1) { cookie += ","; } } set_cookie('time_range', cookie, 365); } function change_text(id, value) { var text = "表示期間
"; switch(value) { case -4: text += "24時間"; break; case -3: text += "48時間"; break; case -2: text += "7日間"; break; case -1: text += "30日間"; break; case 0: text += "60日間"; break; } jQuery(id).html(text); } function make_vertical_slider(id, range, values, step) { // y軸範囲調整スライダーの作成 var id_name = '#' + id; $(function() { $(id_name).slider({ orientation : 'vertical', min : range[0], max : range[1], step : step, range : true, values : values, slide : function(e, ui) { if(ui.values[0] == ui.values[1]) { return false; } var count = 0; for(var i = ui.values[0]; i < ui.values[1]; i += 5) { count++; } if(count >= 50) { $(this).slider('option', 'step', 50); } else { $(this).slider('option', 'step', 5); } }, change : function(e, ui) { var sp = e.target.id.split('_'); var sp2 = sp[sp.length - 1].split('ge'); var id_category = sp[0]; var id_num = sp2[1]; var id = id_category + id_num; limit_set(id, id_num, ui.values[0], ui.values[1]); }, create : function(e, ui) { var values = $(this).slider('option', 'values'); var sp = e.target.id.split('_'); var sp2 = sp[sp.length - 1].split('ge'); var id_category = sp[0]; var id_num = sp2[1]; var id = id_category + id_num; limit_set(id, id_num, values[0], values[1]); } }); }); } function limit_set(id, id_num, min, max) { // y軸範囲変更 const title = item_list[id_num] + "の時間変化"; range[id_num][0] = min; range[id_num][1] = max; draw_graph(id, title, data_set[id_num], load_date, limit[id_num], range[id_num], tr_table[time_range[id_num]], color_table[id_num], checkbox[id_num]); } function draw_vertical_slider_tick(context, range, y_min) { // y軸範囲調整スライダーの目盛り描画 var count = 0; var step = 5; for(var i = range[0]; i < range[1]; i += 5) count++; if(count >= 50) { count = 0; for(var i = range[0]; i < range[1]; i+= 50) count++; step = 50; } for(var i = 0; i <= count; i++) { context.strokeStyle = "#afafaf"; context.moveTo(33, y_min + i * (320 / count)); context.lineTo(41, y_min + i * (320 / count)); var text = "" + (range[1] - step * i); var text_w = context.measureText(text).width; context.fillText(text, 30 - text_w, y_min + i * (320 / count) + 5); } context.stroke(); } function draw_range_line(context, limit, range, x_min, y_min, y_max) { var count = 0; for(var i = limit[0]; i < limit[1]; i += 5) count++; context.beginPath(); context.strokeStyle = "#afafaf"; context.moveTo(x_min, y_min); context.lineTo(x_min - 37, y_min - ((range[1] - limit[1]) / 5) * (320 / count)); context.moveTo(x_min, y_max); context.lineTo(x_min - 37, y_min - ((range[0] - limit[1]) / 5) * (320 / count)); context.closePath(); context.stroke(); context.strokeStyle = "#000000"; } function make_check_box(check_id, btn_id, check_list, color_table, state_list) { // チェックボックスの作成 var el = document.createElement("div"); var text = ""; text += '
'; text += ''; el.innerHTML += text; document.getElementById(btn_id).appendChild(el); el = document.createElement("div"); text = ""; for(var i = 0; i < check_list.length; i++) { text += '' + check_list[i]; text += '= value) min = value; if(max <= value) max = value; } } } } if(min <= limit[0]) min = limit[0]; if(max >= limit[1]) max = limit[1]; // stepで割り切れる値に調整 for(var i = limit[0]; i <= limit[1]; i += step) { if(min >= i && min < i + step) min = i; if(max > i && max <= i + step) max = i + step; } var count = 0; for(var i = min; i < max; i += step) count++; if(count >= 50) { for(var i = limit[0]; i <= limit[1]; i += 50) { if(min >= i && min < i + 50) min = i; if(max > i && max <= i + 50) max = i + 50; } } if(min >= max) { return [limit[0], limit[1]]; } return [min, max]; } function auto_regulate(num) { // 『自動調整』ボタンを押した時の処理 const ran = regulate_range(limit[num], data_set[num], checkbox[num], 5); const s_id = "past_temp_range" + num; //jQuery(s_id).slider('option', 'values', ran); make_vertical_slider(s_id, limit[num], ran, 5); }