インストール

ここでは『旅ログviewer sio-musubi』のインストールのしかたを説明します。

プログラムは HTML と JavaScript で作成しており、改ざん防止のためにソースコードを開示しています。お手数ですがこれをファイル化していただきます。

目次

1. ファイル構成

はフォルダ

tlv(任意)

 css  getCoord_style.css 座標取得ツール用
 sm_style_01-00.css 旅ログviewer(map2画面(デフォルト))用
 sm_style_map1_01-00.css 旅ログviewer(map1画面)用
 images  marker-icon-violet.png 旅ログviewer用
 shadow.png 旅ログviewer用
 sio-musubi.png 旅ログviewer用
 xcross.gif 座標取得ツール用
 js  getCoord.js 座標取得ツール用
 L.KML.js Leafletでkmlファイルを扱うためのプラグイン
 sm_01-00.js 旅ログviewer用
 getCoord.html 座標取得ツール
   sio-musubi_01-00.html 旅ログviewer
 

Fig.1-06

2. フォルダの作成

Fig.1-06 のようにローカルドライブ(例えばD:)の任意のフォルダ(例えば「tlv」)下に「css」「images」「js」フォルダを作成します。

3. 開示コードをファイル化して保存

html、css、js ファイルのコードを以下に開示しますので、コピーして「メモ帳」またはテキストエディタに貼り付け、名前をつけて該当フォルダに保存します。※コードリストの右肩にコピーボタン(クリップボードのマーク)があります。保存するさいの文字コードは「UTF-8」です。

リスト  getCoord_style.css

@charset "UTF-8";
 
.frame {
  display: flex;
}
 
.left,
.right {
  width: 40vw;
  padding: 1em;
}
 
.title {
  text-align: center;
  font-size: 28px;
}
 
#closs {
  font-size: xx-large;
  color: red;
}
 
#tCoord {
  width: 200px;
  background-color: lightyellow;
}
 
#LatInt,
#LngInt {
  width: 30px;
  background-color: pink;
}
 
#LatDec,
#LngDec {
  width: 100px;
  background-color: palegreen;
}
 
#allclear {
  width: 100px;
  height: 50px;
  border-radius: 10px;
  background-color: pink;
  margin-left: 10px;
}
 
#clear {
  width: 100px;
  height: 50px;
  border-radius: 10px;
  background-color: palegreen;
  margin-left: 10px;
}
 
#move {
  width: 100px;
  height: 50px;
  border-radius: 10px;
  background-color: aqua;
  margin-left: 10px;
}
 
#tmap {
  width: 80vw;
  height: 50vh;
  border: 5px solid darkblue;
  margin: 10px 2px;
}

リスト  sm_style_01-00.css

@charset "UTF-8";
 
body {
  background-color: #ddd;
}
 
p {
  text-indent: 1em;
  line-height: 1em;
}
 
#signboard {
  text-align: center;
  margin-top: 2.5em;
}
 
#program_name {
  font-size: 28px;
  color: white;
  background-color: rgba(156, 12, 185, 0.897);
  box-shadow: 4px 4px #555;
  border-radius: 10px;
}
 
#name-description {
  margin-top: 2em;
}
 
#name,
#description {
  background-color: #eee;
}
 
.container {
  display: flex;
}
 
#mp4_file,
#kml_file {
  color: mediumvioletred;
}
 
#reset_mp4_file,
#reset_kml_file {
  visibility: hidden;
}
 
#t_video {
  width: 59vw;
  height: 65vh;
  margin-top: 10px;
  border: 5px solid darkblue;
}
 
.map {
  display: flex;
}
 
#c_map,
#t_map {
  width: 18.5vw;
  height: 65vh;
  margin-top: 10px;
  border: 5px solid darkblue;
}
 
#cLat,
#cLng {
  background-color: lightyellow;
}
 
#all_reset {
  color: #fff;
  background-color: #49a9d4;
  border-radius: 10px;
}
 
#copyright {
  background-color: white;
}

リスト  sm_style_map1_01-00.css

@charset "UTF-8";

body {
  background-color: #ddd;
}

p {
  text-indent: 1em;
  line-height: 1em;
}

#signboard {
  text-align: center;
  margin-top: 2.5em;
}

#program_name {
  font-size: 28px;
  color: white;
  background-color: rgba(156, 12, 185, 0.897);
  box-shadow: 4px 4px #555;
  border-radius: 10px;
}

#name-description {
  margin-top: 2em;
}

#name,
#description {
  background-color: #eee;
}

.container {
  display: flex;
}

#mp4_file,
#kml_file {
  color: mediumvioletred;
}

#reset_mp4_file,
#reset_kml_file {
  visibility: hidden;
}

#t_video {
  width: 59vw;
  height: 65vh;
  margin-top: 10px;
  border: 5px solid darkblue;
}

.map {
  display: flex;
}

#c_map {
  width: 38vw;
  height: 65vh;
  margin-top: 10px;
  border: 5px solid darkblue;
}

#cLat,
#cLng {
  background-color: lightyellow;
}

#all_reset {
  color: #fff;
  background-color: #49a9d4;
  border-radius: 10px;
}

#copyright {
  background-color: white;
}

リスト  getCoord.js

//全コンテンツを読み込んでからの処理
window.addEventListener('DOMContentLoaded', function(){
 
    // マップの中心に東京駅を表示(初期設定)
    const TOKYOSTATION=[35.681298, 139.7662469];
 
    //mapを作成
    var mymap = L.map('tmap').setView(TOKYOSTATION, 16);
    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
	    maxZoom: 18,
	    /* 著作権者表示 */
	    attribution: 'Map data © OpenStreetMap contributors, '
    }).addTo(mymap);
    // 位置表示に+アイコン指定
    var myicon = new L.icon({iconUrl : 'images/xcross.gif', iconRetinaUrl : 'images/xcross.gif', iconSize : [32, 32], iconAnchor : [16, 16]});
    myicon.options.shadowSize = [0,0];
    var markerSP=L.marker(TOKYOSTATION, {icon : myicon}).addTo(mymap);
    outputTargetCoord(mymap);
 
//-------------------- getCoord part ------------------------------
    mymap.on('move', function(e){
        markerSP.setLatLng(mymap.getCenter());
        outputTargetCoord(mymap);
    });
 
    function outputTargetCoord(map){
        var tPos = map.getCenter();
        var tCoord = Math.round(tPos.lng*1000000)/1000000 + ',' + Math.round(tPos.lat*1000000)/1000000 + ',' + '30';
 
        document.getElementById('targetLat').innerHTML = tPos.lat;
        document.getElementById('targetLng').innerHTML = tPos.lng;
        document.getElementById('tCoord').value = tCoord;
 
    };
 
//-------------------- setCoord part -------------------------------
    //LatLng入力欄のall clear
    document.getElementById('allclear').addEventListener('click', function(e){
        document.getElementById('LatInt').value = '';
        document.getElementById('LatDec').value = '';
        document.getElementById('LngInt').value = '';
        document.getElementById('LngDec').value = '';
    });
 
    //LatLng小数入力欄の clear
    document.getElementById('clear').addEventListener('click', function(e){
        document.getElementById('LatDec').value = '';
        document.getElementById('LngDec').value = '';
    });
 
    //指定座標に移動
    document.getElementById('move').addEventListener('click', function(e){
        var mLat = 0;
        var mLng = 0;
        var mLatInt = document.getElementById('LatInt').value;
        var mLatDec = document.getElementById('LatDec').value;
        var mLngInt = document.getElementById('LngInt').value;
        var mLngDec = document.getElementById('LngDec').value;
        mLat = Number.parseFloat(mLatInt + '.' + mLatDec);
        mLng = Number.parseFloat(mLngInt + '.' + mLngDec);
        mymap.panTo([mLat,mLng]);
    });
 
}, true);

リスト  sm_01-00.js

//---------------------- 利用条件 --------------------------------------
// 「旅ログviewer sio-musubi」(以下、本ソフトウェア)はフリーソフトです。
// 著作権は「旅ログviewer」ウェブサイト https://tabilogviewer.com の管理者
// thirdya.su@tabilogviewer.com にあります。
// 改ざん防止のため、コピーおよび改造品の配布・転載を禁止します。
// 開発には細心の注意を払っていますが、本ソフトウェアを使用したことに起因する
// 如何なる結果について、作成者は一切責任を負いません。
// 使用者の責任においてご利用ください。
// 本ソフトウェアは、以上の条件を承諾された方のみご利用いただけます。
//-------------------------------------------------------------------------
 
 
//全コンテンツを読み込んでからの処理
window.addEventListener('DOMContentLoaded', function(){
//---------------- グローバル変数他 --------------------------------------
    var movieTime = 0;              //video再生時間(ミリ秒)
    var currentTime = 0;            //video再生位置(ミリ秒)
    var timerID = -1;               //タイマーID
    const INTERVAL = 100;             //videoと座標の紐付けチェック間隔(ミリ秒)
    var tVideo = document.getElementById("t_video");
    var icoords = [];               //全行程の座標配列
    var cTrack = {};                //cmapのトラック
    var tTrack = {};                //tmapのトラック
    var points = 0;                 //全行程の地点数;
 
// ----------------  videoパート ------------------------------------------
 
    //mp4ファイルが選択された際の処理
    document.getElementById("mp4_file").addEventListener('change', function(ev){
        var mp4Files = ev.target.files;
        var mp4File = mp4Files[0];
        if(!mp4File)return;
        var objurl = URL.createObjectURL(mp4File);
        tVideo.src = objurl;
        tVideo.onloadeddata = function(){
            movieTime = tVideo.duration;
            document.getElementById("movieTime").innerHTML = movieTime;
            pointInterval();
        }
    }, true);
 
    //videoスライダック変更時の処理(再生位置取得)
    document.getElementById("t_video").addEventListener('seeked', function(ev){
        changeCurrentTime();
        document.getElementById("currentTime").innerHTML = Math.round(currentTime);
    }, true);
 
    //video再生時の処理(再生位置の取得(繰り返し))
    document.getElementById("t_video").addEventListener('play', function(ev){
        timerID = setInterval(function(){
            changeCurrentTime();
        }, INTERVAL);
    }, true);
 
    //video一時停止時の処理(再生位置の取得繰り返しの停止)
    document.getElementById("t_video").addEventListener('pause', function(ev){
        clearInterval(timerID);
        timerID = -1;
    }, true);
 
    //mp4ファイル選択のリセット時の処理
    document.getElementById("reset_mp4_file").addEventListener('click', function(ev){
        clearVideo();
    }, true);
 
    //videoとmovieTimeのクリア
    function clearVideo(){
        tVideo.src = "";
        movieTime = 0;
        currentTime = 0;
        document.getElementById("movieTime").innerHTML = movieTime;
        document.getElementById("currentTime").innerHTML = currentTime;
        pointInterval();
    }
 
    function changeCurrentTime(){
        currentTime = tVideo.currentTime;
        document.getElementById("currentTime").innerHTML = Math.round(currentTime);
        currentPoint(currentTime);
    }
 
// ------------------- mapパート ------------------------------------------------
 
    // マップの中心に東京駅を表示(初期設定)
    const TOKYOSTATION={lat:35.681298, lng:139.7662469};
 
    //拡大地図cMapを作成
    var cMymap = L.map('c_map').setView(TOKYOSTATION, 16);
    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
	    maxZoom: 18,
	    /* 著作権者表示 */
	    attribution: 'Map data © OpenStreetMap contributors, '
    }).addTo(cMymap);
    // 位置表示アイコン指定
    var myicon = new L.icon({iconUrl : 'images/marker-icon-violet.png', iconRetinaUrl : 'images/marker-icon-violet.png', iconSize : [25, 41], iconAnchor : [13, 41],
     shadowUrl : 'images/shadow.png', shadowRetinaUrl : 'images/shadow.png',shadowSize : [45, 41], shadowAnchor : [23, 41]});
    var cMarkerSP=L.marker(TOKYOSTATION, {icon : myicon}).addTo(cMymap);
 
    //行程全体を含む縮小地図tMapを作成
    var tMymap = L.map('t_map').setView(TOKYOSTATION, 10);
    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
	    maxZoom: 18,
	    /* 著作権者表示 */
	    attribution: 'Map data © OpenStreetMap contributors, '
    }).addTo(tMymap);
    var tMarkerSP=L.marker(TOKYOSTATION, {icon : myicon}).addTo(tMymap);
    displayLatLng(TOKYOSTATION);
 
    //kmlファイルが選択された際の処理
    document.getElementById("kml_file").addEventListener('change', function(e){
        var inputKml=document.getElementById("kml_file").files[0];
	    var reader=new FileReader();
        reader.readAsText(inputKml, 'UTF-8');
	    reader.addEventListener('load', function(){
            var kmltext = reader.result;
            var parser = new DOMParser();
            var kml = parser.parseFromString(kmltext, 'text/xml');
 
            //---------------------- タイトルと詳細の表示 ----------------------------------
            document.getElementById('name').innerHTML = getName(kml);
            document.getElementById('description').innerHTML = getDescription(kml);
 
            //name(タイトル)を取得
            function getName(xml){
                var el = xml.getElementsByTagName('name');
                var text = '(なし)';
                var child;
                var containflag = 0;
                for(var j = 0; j < el.length; j++){
                    child = el[j].parentNode.lastChild;
                    while(child){
                        if(child.tagName == 'LineString'){
                            if(typeof el[j].childNodes[0] === 'undefined'){
                                ;
                            }else{
                                text = el[j].childNodes[0].nodeValue;
                            }
                            text = ' ' + text + ' ';
                            containflag = 1;
                            break;
                        }
                        child = child.previousSibling;
                    }
                    if(containflag == 1){
                        break;
                    }
                }
                return text;
            }
 
            //description(詳細)を取得
            function getDescription(xml){
                var el = xml.getElementsByTagName('description');
                var text = '(なし)';
                var child;
                var containflag = 0;
                for(var j = 0; j < el.length; j++){
                    child = el[j].parentNode.lastChild;
                    while(child){
                        if(child.tagName == 'LineString'){
                            if(typeof el[j].childNodes[0] === 'undefined'){
                                ;
                            }else{
                                text = el[j].childNodes[0].nodeValue;
                            }
                            text = ' ' + text + ' ';
                            containflag = 1;
                            break;
                        }
                        child = child.previousSibling;
                    }
                    if(containflag == 1){
                        break;
                    }
                }
                return text;
            }
            //---------------------------- 地図の処理 ----------------------------------------
            //全行程の座標配列icoordsの取得
            icoords = getLatLngs(kml);
 
            //全行程他の表示
            cTrack = new L.KML(kml);
            tTrack = new L.KML(kml);
            cMymap.addLayer(cTrack);
            tMymap.addLayer(tTrack);
 
            //表示位置を行程のスタート地点に変更
            mapPanTo(icoords[0]);
            markerSetLatLng(icoords[0]);
            displayLatLng(icoords[0]);
 
            //軌跡ポイント数の表示
            points = icoords.length;
            document.getElementById('points').innerHTML = points;
            pointInterval();
 
            //LineStringのcoordinates要素を取得
            function getLatLngs(xml){
                var el = xml.getElementsByTagName('coordinates');
                for(var j = 0; j < el.length; j++){
                    if(el[j].parentNode.tagName == 'LineString'){
                        //console.log(el[j].parentNode.tagName);
                        var coords = [];
                        coords = coords.concat(readCoords(el[j]))
                    }
                }
                return coords;
            }
 
            function readCoords(el){
                var text = '', coord = [], i;
                for (i = 0; i < el.childNodes.length; i++) {
                    text = text + el.childNodes[i].nodeValue;
                }
                text = text.split(/[\s\n]+/);
                for (i = 0; i < text.length; i++) {
                    var ll = text[i].split(',');
                    if (ll.length < 2) {
                        continue;
                    }
                    coord.push(new L.LatLng(ll[1], ll[0]));
                }
                return coord;
            }
 
 	    }, true);
    }, true);
 
    //現在地(地図)の更新
    function currentPoint(currentTime){
        var m = icoords.length;
        var n = Math.round((m * currentTime) / movieTime);
        mapPanTo(icoords[n]);
        markerSetLatLng(icoords[n]);
        displayLatLng(icoords[n]);
    }
 
    //kmlファイル選択のリセット時の処理
    document.getElementById("reset_kml_file").addEventListener('click', function(ev){
        clearMap();
        document.getElementById('name').innerHTML = '';
        document.getElementById('description').innerHTML = '';
    }, true);
 
 
    //指定ポイントを中心に地図を移動
    function mapPanTo(latLng){
        cMymap.panTo(latLng);
        tMymap.panTo(latLng);
    }
    //指定ポイントにマーカーを移動
    function markerSetLatLng(latLng){
        cMarkerSP.setLatLng(latLng);
        tMarkerSP.setLatLng(latLng);
    }
 
    //現在地の緯度、経度表示
    function displayLatLng(latLng){
        document.getElementById('cLat').value = latLng.lat;
        document.getElementById('cLng').value = latLng.lng;
    }
 
    //mapのクリア
    function clearMap(){
        icoords = [];
        points = 0;
        cMymap.removeLayer(cTrack);
        tMymap.removeLayer(tTrack);
        mapPanTo(TOKYOSTATION);
        markerSetLatLng(TOKYOSTATION);
        displayLatLng(TOKYOSTATION);
        document.getElementById('points').innerHTML = points;
        document.getElementById('pointInterval').innerHTML = 0;
        pointInterval();
    }
 
    //ポイント間隔の表示
    function pointInterval(){
        if(movieTime * points){
            document.getElementById('pointInterval').innerHTML = Math.round((movieTime/points)*100)/100;
        }
    }
 
//---------------------- mp4、kmlファイル選択のクリア -------------------------
document.getElementById('all_reset').addEventListener('click', function(ev){
    document.getElementById('reset_mp4_file').click();
    document.getElementById('reset_kml_file').click();
})
 
}, true);

リスト  getCoord.html

<!DOCTYPE html>
    <html lang="ja">
        <head>
            <title>getCoord</title>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
           integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
           crossorigin=""/>
             <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
           integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
           crossorigin=""></script>
            <script src="JS/getCoord.js"></script>
            <link href = "css/getCoord_style.css" rel = "stylesheet" type="text/css">
        </head>
        <body>
          <div class="frame">
            <div class="left">
                <p><span class='title'>座標取得パート</span></p>
                <p>目的の地点を<span id=closs>+</span>の中心に合わせることで<br>
                   kmlファイル用の座標データ(小数点以下6桁)を表示します。</p>
                <p>コピー&ペーストに使ってください。</p>
                <p>緯度 :<span id="targetLat">0</span></p>
                <p>経度 :<span id="targetLng">0</span></p>
                <p>kmlファイル用座標データ <input type="text" id="tCoord" readonly></p>
                <p>※末尾の30は高度のダミー、旅ログviewerでは無視されます。</p>
            </div>
            <div class="right">
                <p><span class='title'>地図移動パート</span></p>
                <p>緯度、経度を入力して「移動」ボタンを押してください。</p>
               <p>座標が欲しい地点に近い地点に地図を移動するために使ってください。</p>
               <p>緯度 :<span><input type="text" id="LatInt"></span> . <span><input type="text" id ="LatDec"></span></p>
               <p>経度 :<span><input type="text" id="LngInt"></span> . <span><input type="text" id ="LngDec"></span></p>
               <p>※「全クリア」は入力値全てをクリア、「クリア」は小数点以下をクリアします。</p>
               <p><button id="allclear">全クリア</button><button id="clear">クリア</button><button id="move">移動</button></p>
            </div>
          </div>
            <div id='tmap'></div>
        </body>
    </html>

リスト  sio-musubi_01-00.html

<!DOCTYPE html>
<html lang="ja">
  <head>
      <title>sio-musubi</title>
      <meta charaset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
	   integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
	   crossorigin=""/>
      <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
	   integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
	   crossorigin=""></script>
      <script src="js/L.KML.js"></script>
      <link href = "css/sm_style_01-00.css" rel = "stylesheet" type="text/css">
      <script src="js/sm_01-00.js"></script>
      <link rel="icon" type="image/png" href="images/sio-musubi.png">
    </head>
    <header>
        <p id="signboard"><span id="program_name"> 旅ログviewer sio-musubi ver 1.0 </span></p>
        <p id='name-description'>タイトル:<span id="name"></span>        詳細:<span id="description"></span></p>
    </header>
    <body>
        <div class="container">
            <main>
                <form >
                    <label for="mp4_file"> mp4 </label>
                    <input id="mp4_file" type="file" accept="video/mp4" value="mp4ファイルの選択">
                    <input id="reset_mp4_file" type="reset" value="リセット">
                </form>
                <!-- video表示位置 -->
                <video id="t_video" controls>
                    <p>お使いのブラウザはvideo要素に対応していません。</p>
                </video>
                <p>再生時間[秒] :<span id="movieTime">0</span></p>
                <p>再生位置[秒] :<span id="currentTime" >0</span></p>
                <p><button id = "all_reset">全クリア</button></p>
                <!-- 著作権表示:削除禁止ここから -->
                <div><a id="copyright" href="https://tabilogviewer.com" target="_blank">Powered by TabiLogViewer</a></div>
                <!-- 著作権表示:削除禁止ここまで -->
            </main>
            <aside>
                <form id="select_file">
                    <label for="kml_file"> kml </label>
                    <input id="kml_file" type="file" accept=".kml" value="kmlファイルの選択">
                    <input id="reset_kml_file" type="reset" value="リセット">
                </form>
                <div class="map">
                <!-- マップ表示位置 -->
                    <div id="c_map"></div>
                    <div id=t_map></div>
                </div>
                <p>現在地 緯度 :<input type="text" id="cLat" readonly></p>
                <p>現在地 経度 :<input type="text" id="cLng" readonly></p>
                <p>行程ポイント数 :<span id="points">0</span></p>
                <p>行程ポイント間隔[秒] :<span id="pointInterval">0</span></p>
            </aside>
        </div>
    </body>
    <footer>
    </footer>
</html>

4. L.KML.js の入手

「L.KML.js」は Leaflet の公式サイト https://leafletjs.com から入手します。

「Plugins」をクリックします。

「Overlay data formats」をクリックします。

「leaflet-kml」をクリックします。

「↓Code」のプルダウンメニューの「Download ZIP」をクリックしてダウンロードします。ダウンロードした「leaflet-kml-master.zip」中に「L.KML.js」ファイルがあります。

5. イメージファイルの保存

イメージを右クリックして「名前を付けて保存」します。

marker-icon-violet.png
shadow.png
sio-musubi.png
xcross.gif

6. 旅ログviewer sio-musubi を起動して確認

「sio-musubi_01-00.html」をクリックして『旅ログviewer sio-musubi』を起動します。

Fig.1-07

Fig.1-07 のように表示されればインストールできています。