cb37の日記

地理情報系大学院生

Leaflet を使ったWifi スポットの可視化

概要

JavaScriptインタラクティブ地図ライブラリであるLeafletを使ってみたので備忘録です.いつもはPythonのfoliumという,Leafletのhtmlファイルを生成するライブラリで作業しているのですが,諸事情でJavaScriptを使う用事があったので使ってみました.JavaScript自体はNode.jsでゲームを作ったりした経験があるので初めてではないのですが,割と忘れていましたね.

やってみたのはLeafletを使ったWifiスポットの可視化です.ただ地図を表示するだけでは味気ないと思ったからで,特にそこに深い意味はないです.データは130001_東京都_公衆無線LAN - FREE Wi-Fi & TOKYO スポット情報 を使いました.説明は次のようになっています.

外国人旅行者等が多く訪れる都立施設などにおいて無料で利用できる公衆無線LANWi-Fi)サービス「FREE Wi-Fi & TOKYO」のスポット一覧です。 中身を見るとあまり多くのデータが含まれているわけではないです.東京ならカフェや飲食店みたいなところの方が多いかもしれませんが,テストなので丁度いいと思います.

最近はデジタル庁のおかげなのか,少しずつオープンデータが増えてきてうれしい限りです.自分は,データはものづくりにおける材料だと思っています.一つ公開されるだけでも,既存のものとの組み合わせることでさらに面白いものが作れると思っているので,今後もこの方向でいってほしいものです.

実装

csvファイルを読み込むところでエラーが.

Access to XMLHttpRequest at 'file://wsl%24/Ubuntu-20.04/home/{path}/wifispot/freewifiandtokyo.csv' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.

こちらで解決でした.【Ajax】ローカルファイルを読み込もうとしたらCORSエラーが発生したので解決した - Qiita

やることは,

  • 場所名が入っているのでピンを立てて名前を出す.
  • また,Wifiの届く範囲を円で示す.

ただ両方だと見づらいのでボタンを付けて切り替えられるようにしました.

コード

<!DOCTYPE html>
<html>
<head>
    <title>Wifi_Spot.html</title>
    <meta charset="utf-8" />
    <link rel = "stylesheet" href = "https://unpkg.com/leaflet@1.4.0/dist/leaflet.css" />
    <script src = "https://unpkg.com/leaflet@1.4.0/dist/leaflet.js"></script>
    <script>
        let csvdata = [];
        let visibleCircle = true;
        let visibleMarker = true;
        var my_map;

        //CSVファイルを読み込む関数getCSV()の定義
        function getCSV(){
            return new Promise(function(resolve, reject){
                var req = new XMLHttpRequest(); // HTTPでファイルを読み込むためのXMLHttpRrequestオブジェクトを生成
                req.open("get", "freewifiandtokyo.csv", true); // アクセスするファイルを指定
                req.overrideMimeType('text/plain; charset=Shift_JIS');
                req.send(null); // HTTPリクエストの発行
                
                // レスポンスが返ってきたらconvertCSVtoArray()を呼ぶ    
                req.onload = function(){
                    convertCSVtoArray(req.responseText); // 渡されるのは読み込んだCSVデータ
                    resolve();
                }
            });
        }
        // 読み込んだCSVデータを二次元配列に変換する関数convertCSVtoArray()の定義
        function convertCSVtoArray(str){ // 読み込んだCSVデータが文字列として渡される
            var result = []; // 最終的な二次元配列を入れるための配列
            var tmp = str.replace("\\r", "");
            tmp = tmp.split("\n"); // 改行を区切り文字として行を要素とした配列を生成

            // 各行ごとにカンマで区切った文字列を要素とした二次元配列を生成
            for(var i=0;i<tmp.length;++i){
                result[i] = tmp[i].split(',');
            }
            csvdata = result;
        }

        // 
        function init() {
            if (my_map != undefined) { my_map.remove(); }
            my_map = L.map('map').setView([35.65809922, 139.74135747], 12);
            mapLink = '<a href="https://openstreetmap.org">OpenStreetMap</a>';
            L.tileLayer(
                'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                    attribution: 'Map data &copy; ' + mapLink,
                    maxZoom: 18
                }).addTo(my_map);

                // 処理
                getCSV().then(function(){

                    for (let i=1; i<csvdata.length-1; i++){
                        if(visibleCircle){
                            L.circle([Number(csvdata[i][3]), Number(csvdata[i][4])], {
                                radius: 500,
                                color: 'blue',
                                fillColor: '#399ade',
                                fillOpacity: 0.3
                                }).addTo(my_map);
                        }
                        if(visibleMarker){
                            L.marker([Number(csvdata[i][3]), Number(csvdata[i][4])]).addTo(my_map).bindTooltip(csvdata[i][1]);
                        }
                    };
                });

        }

        function drawCircle(){
            for (let i=1; i<csvdata.length-1; i++){
                L.circle([Number(csvdata[i][3]), Number(csvdata[i][4])], {
                    radius: 500,
                    color: 'blue',
                    fillColor: '#399ade',
                    fillOpacity: 0.3
                    }).addTo(my_map);
            };
        };

        function drawMarker(){
            for (let i=1; i<csvdata.length-1; i++){
                L.marker([Number(csvdata[i][3]), Number(csvdata[i][4])]).addTo(my_map).bindTooltip(csvdata[i][1]);
            };
        };

        function switchCircle(){
            visibleCircle = !visibleCircle;
            init();
        }

        function switchMarker(){
            visibleMarker = !visibleMarker;
            init();
        }
    </script>
</head>
<body onload="init()">
    <div id="map" style="width: 100%; height: 800px; border: solid 1px"></div>
    <button class="visible circle" type="button" onclick="switchCircle();">Circle</button>
    <button class="visible marker" type="button" onclick="switchMarker();">Marker</button>
</body>
</html>

関連リンク