HTML5で各電力会社の電力使用率をアナログメーターで描画するサンプルを作ってみた。

今年も凄く暑くなってきて、節電も気になり始めたんで、また電力ネタを。
以前、電力使用率を表示するガジェットを作成したけど、Windows8からデスクトップガジェットが使えなくなってしまった
なので、Windows8上でも簡単に表示できるよう、HTML上で表示できる電力メーターを作ってみた。
丁度、HTML5のスキルアップもしたかったので、Flashのような絵が描けるを使って作ることに。
でも、テキストエディタのみで、メーターのイメージを想像しながら作るのは、ちょっと難しかった。。
かなり試行錯誤を繰り返す羽目に。
それでも、なんとかイメージに近いものが出来上がった。
meter
一応グラデーションとか光沢など余計なものも作り込んである。
針と文字は、もうちょい何とかしたかったけど。
特にアプリ化する予定も無く、これで終わりだけど、勿体ないのでOsadaSoft実験室というページを作り、そこに載せて置くことにした。

HTML5+Ajaxによる電力メーター

<2022/7/2追記>
さすがに9年経って動かなくなってた(Yahoo!電力使用状況APIが閉鎖)。
APIを利用せず、各電力会社のCSVデータから情報取得するよう修正中しました。
関西電力のみ微妙にCSVデータが異なるものの、各社同じCSV形式だったので助かった。
また突然仕様変更等で使えなくなる可能性もありますが、とりあえず復活。

各電力会社のデータ(csv)取得元:

北海道電力https://denkiyoho.hepco.co.jp/area_forecast.html
東北電力https://setsuden.nw.tohoku-epco.co.jp/graph.html
北陸電力https://www.rikuden.co.jp/nw/denki-yoho/
東京電力https://www.tepco.co.jp/forecast/
中部電力https://powergrid.chuden.co.jp/denkiyoho/
関西電力https://www.kansai-td.co.jp/denkiyoho/
中国電力https://www.energia.co.jp/nw/jukyuu/
四国電力https://www.yonden.co.jp/nw/denkiyoho/
九州電力https://www.kyuden.co.jp/td_power_usages/pc.html
沖縄電力https://www.okiden.co.jp/denki2/

一応、HTML5で作っているので、最新ブラウザであれば、割とうまく表示できると思う。
まだHTML5自体が仕様Fixしていない(W3CのHTML5勧告は2014年予定)ので、ブラウザによって表示できない部品もある。
例えば、スライダーバーのようなは、Google Crome、Safariなどでは表示できるけど、
Internet Exprolerや、FireFoxでは未対応。
多分、W3Cの仕様Fix前に作り込んでしまうと、後々仕様変更があった場合のユーザー影響があるので、あえて作り込んでいないような。
iphone
一応、iPhone(Safari)でも表示できた。
HTMLソース:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>OsadaSoft実験室・HTML5+Ajaxによる電力メーター</title>
    <script>
    // グローバル変数宣言
    var denUsageRate;       // 電力使用率(初期値は最大値の100)
    var wkDenryoku;         // 描画中の電力会社
    var wkUsageRate;        // 描画中の針の値
    var needleTimer=null;   // 針描画用タイマー
    var den={hokkaido:"北海道電力",tohoku:"東北電力",tokyo:"東京電力",chubu:"中部電力",kansai:"関西電力",kyushu:"九州電力"};
    // 電力使用状況APIのレスポンス結果を処理するコールバック関数

    function powerUsageCallback(json) {
        if(needleTimer!=null) return;
        var usageVal = json.ElectricPowerUsage.Usage.$;
        var CapVal = json.ElectricPowerUsage.Capacity.$;
        denUsageRate = toInt((usageVal/CapVal)*100);
        document.getElementById("resArea").innerHTML =
        "<table border=1>" +
        "<tr><td>Area</td><td>" + json.ElectricPowerUsage.Area + "</td></tr>" +
        "<tr><td>Usage</td><td>" + addFigure(json.ElectricPowerUsage.Usage.$) + " KW</td></tr>" +
        "<tr><td>Capacity</td><td>" + addFigure(json.ElectricPowerUsage.Capacity.$) + " KW</td></tr>" +
        "<tr><td>Date (houre)</td><td>" + json.ElectricPowerUsage.Date + " (" + json.ElectricPowerUsage.Hour + ")</td></tr></table>";
        // 0から取得した値まで10msごとに針描画更新
        needleTimer = setInterval(drawMeter, 10);
    }

    // メーター表示処理
    function showMeter() {
        if(needleTimer!=null) return;
        denUsageRate = 100;
        wkUsageRate = -1;
        var radDen = document.getElementsByName("rDen");
        for(i=0;i<radDen.length;i++){
            if (radDen[i].checked) {
                wkDenryoku = radDen[i].value;
            }
        }

        var aplId = "";     ※ここに自分用のYahoo!デベロッパーネットワークのアプリケーションIDを指定
        var url = "http://setsuden.yahooapis.jp/v1/Setsuden/latestPowerUsage?";
        var params = "appid=" + aplId + "&area=" + wkDenryoku + "&output=json&callback=powerUsageCallback";
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = url + params;
        document.body.appendChild(script);
    }

    // 整数化
    function toInt(val){
        return ~~(val);
    }

    // カンマ区切りの数値に変換
    function addFigure(str) {
        var num = new String(str).replace(/,/g, "");
        while(num != (num = num.replace(/^(-?\d+)(\d{3})/, "$1,$2")));
        return num;
    }

    // Canvas描画処理
    function drawMeter(){
        var canvas  = document.getElementById("myCanvas");
        var cv      = canvas.getContext("2d");
        var scale = document.dForm.meterSize.value *10
        var center  = {x : scale / 2, y : scale / 2};
        var hLen    = scale * 0.8 / 2;      // 針の長さ
        var fSize   = scale / 9;            // フォントサイズ

        // メーター背景の円描画
        cvSize = document.getElementById("myCanvas").getAttribute("width");
        cv.clearRect(0, 0, cvSize, cvSize);
        cv.beginPath();
        cv.arc(center.x , center.y , scale/2 , 0 , Math.PI * 2 , false);

        // グラデーション指定
        var grad = cv.createRadialGradient(center.x , center.y , 0 ,center.x , center.y ,scale/2);
        grad.addColorStop(0.00, "#505050");
        grad.addColorStop(0.40, "#303030");
        grad.addColorStop(0.90, "#101010");
        grad.addColorStop(0.95, "#404040");
        grad.addColorStop(1.00, "#000000");
        cv.fillStyle = grad;
        cv.fill();
        // Canvasの色、フォント
        cv.fillStyle    = "#FFFFFF";
        cv.font         = "bold " + fSize + "px 'MS Pゴシック'";
        // 文字盤表示
        for(var i=0;i<=10;i++){
            var radian = ((270 / 10) * i +180) * Math.PI / 180;
            var xx = center.x + hLen * Math.sin(radian) - fSize/4;
            var yy = center.y - hLen * Math.cos(radian) + fSize/4;
            cv.fillText(i, xx, yy);
        }

        // 針を指定値まで増加させていく
        if(wkUsageRate==-1){
            wkUsageRate=0;
        }else{
            addVal = toInt((denUsageRate - wkUsageRate) / 20);
            if(addVal<1) addVal = 1;
            wkUsageRate += addVal;
        }
        if(wkUsageRate>=denUsageRate){
            clearInterval(needleTimer);
            needleTimer=null;
        }

        // 値表示
        cv.fillStyle    = "#B0B0B0";
        cv.font = fSize * 0.7 + "px 'MS Pゴシック'";
        cv.fillText(den[wkDenryoku], center.x + scale/20, center.y + scale/8);
        cv.fillText(wkUsageRate + " % ", center.x + scale/10, center.y + scale/4);

        // 針(影)描画
        var hRadian = ((270 * wkUsageRate / 100) + 180) * Math.PI / 180;
        var pos_x = cPoint(center, hLen, hRadian);
        cv.strokeStyle = "#550000";
        cv.lineWidth = scale / 40;
        cv.beginPath();
        cv.moveTo(center.x, center.y);
        cv.lineTo(pos_x.x, pos_x.y);
        cv.moveTo(0,0);
        cv.stroke();

        // 針(中心)描画
        cv.strokeStyle = "#FF5555";
        cv.lineWidth = scale / 100;
        cv.beginPath();
        cv.moveTo(center.x, center.y);
        cv.lineTo(pos_x.x, pos_x.y);
        cv.moveTo(0,0);
        cv.stroke();
        cv.fillStyle = 'rgb(50, 50, 50)';
        cv.arc(center.x , center.y , scale/20 , 0 , Math.PI * 2 , false);
        cv.fill();

        // 光沢を付ける(半透明の円描画)
        cv.fillStyle = 'rgba(224, 224, 224, 0.1)';
        cv.arc(center.x , center.y/20 , scale/1.5 , 0 , Math.PI * 2 , false);
        cv.fill();
    }

    // 針先端の座標取得
    var cPoint = function(center, hookLength, radian) {
        return {
            x : center.x + hookLength * Math.sin(radian),
            y : center.y - hookLength * Math.cos(radian)
        };
    }
    </script>
</head>
<body onload="showMeter()">
    <h3>HTML5+Ajaxによる電力メーター</h3>
    <a href="http://developer.yahoo.co.jp/webapi/shinsai/setsuden/v1/latestpowerusage.html" target="_blank">Yahoo!電力使用状況API</a>
    から各電力会社の電力使用量を取得し、電力使用率をHTML5の<Canvas>にアナログ風メーターとして描画するサンプルです。<br>
    <br>
    <hr>
    <div style="width:100%;">
        <form name="dForm">
            <fieldset style="display:inline;">
                <legend>電力会社</legend>
                <input type=radio name="rDen" onClick="showMeter()" value="hokkaido" >北海道電力
                <input type=radio name="rDen" onClick="showMeter()" value="tohoku">東北電力
                <input type=radio name="rDen" onClick="showMeter()" value="tokyo" checked>東京電力
                <input type=radio name="rDen" onClick="showMeter()" value="chubu">中部電力
                <input type=radio name="rDen" onClick="showMeter()" value="kansai">関西電力
                <input type=radio name="rDen" onClick="showMeter()" value="kyushu">九州電力
            </fieldset>
            <fieldset style="display:inline;">
                <legend>メーター描画サイズ</legend>
                小<input type="range" name="meterSize" min="10" max="40" value="20" onchange="showMeter()">大
            </fieldset>
        </form>
        <br><br>
        <table>
            <tr><td>
            <canvas id="myCanvas" width="400" height="400" style="background-color:#E0E0E0;"></canvas>
            </td><td>
            電力使用状況API レスポンス結果<br><br>
            <div id="resArea">Yahoo! API Result Area</div>
            </td></tr>
        </table>
        <br><br>
    </div>
    <hr>
    <br>
    ※HTML5対応ブラウザで表示してください。<br>
</body>
</html>

※aplIdには、自分のYahoo!デベロッパーネットワークのアプリケーションIDを指定しなおして頂戴。

← ブログ一覧へ戻る