2014年7月14日月曜日

GNSS/GPS 経路の表示に OpenLayers 2 を使う(その9:今回の一連のものをまとめたもの)

これはGNSS/GPS 経路の表示に OpenLayers 2 を使う(その8:マーカーと経路を別々の KML ファイルで表示)からの続きである。
GNSS/GPS 経路の表示に OpenLayers 2 を使う(その0:はじめに)に目次がある。
ここでは OpenLayers 2.13.1 を使っている。
前回(その8:マーカーと経路を別々の KML ファイルで表示)では 経路とマーカー用に別々の KML ファイルを用意して,経路とマーカーを地図上に記載する方法を記述した。

今回はこれまでのまとめとして,一連のものをひとまとめにしたものを示そう。 一応,OpenLayers 2.13.1 を使った地理院地図の説明は今回で区切りとしたい。 従って,今回がこのシリーズの最終回である。
 以下に今回の web ソースコードを書いておこう。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta http-equiv="content-style-type" content="text/css">
<meta http-equiv="content-script-type" content="text/javascript">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>KML+Marker+Opacity example</title>
<link rel="stylesheet" type="text/css" href="../../main.css">
<link rel="stylesheet" type="text/css" href="../../cj_map/popup.css">
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script src="../../OpenLayers-2.13.1/lib/OpenLayers.js"></script>
<script type="text/javascript">//<![CDATA[
var param = { div: 'map_canvas', lon: 136.181193333333, lat: 34.2329783333333, zoom: 15, url: 'work/map_data1.kml', url2:'work/wp_data1.kml' };
//]]></script>
<script type="text/javascript">
// -------------------------------------------------------------------
var proj_3857 = new OpenLayers.Projection('EPSG:3857');
var proj_4326 = new OpenLayers.Projection('EPSG:4326'); // WGS84

var map = null;
var std_map = null;
var markers = null;

var gMaxOpacity = 1.0; // 不透明度の最大値
var gMinOpacity = 0.0; // 不透明度の最小値

var crosshairsCursorCtrl = null; // 中心マーカー用 crosshairs の変数
var centercross = 1; // 表示する

var titleImageUrl = "./cjmap_title.png";
var titleImageCtrl = null; // タイトル画像用の変数
var titleimagedisplay = 1; // 表示する
var title_image_size = new OpenLayers.Size(163,21);

var symbolImageUrl = "./cjmap_icons.png";
var symbolImageCtrl = null; // タイトル画像用の変数
var symbolimagedisplay = 1; // 表示する
var symbol_image_size = new OpenLayers.Size(120,144);
// -------------------------------------------------------------------
// 初期化
function init_map() {
        // 地図表示の変数定義
        map = new OpenLayers.Map({ div: param.div, projection: proj_3857, displayProjection: proj_4326 });

        // 地理院地図(標準地図)を半透明にしてoverlay として表示
        std_map = new OpenLayers.Layer.XYZ('地理院地図(標準)', 'http://cyberjapandata.gsi.go.jp/xyz/std/${z}/${x}/${y}.png', {
          attribution: '<a href="http://portal.cyberjapan.jp/help/termsofuse.html" target="_blank">国土地理院</a>',maxZoomLevel: 17, opacity: 1.0, isBaseLayer: false
        });
        // Google Maps(Roadmap)を base layer として表示
        var gmap = new OpenLayers.Layer.Google("Google ROADMAP", { type: google.maps.MapTypeId.RODEMAP, numZoomLevels:22 });
        // Google Maps(Terrain)を base layer として表示
        var gmapT = new OpenLayers.Layer.Google("Google TERRAIN", { type: google.maps.MapTypeId.TERRAIN, numZoomLevels:16 });
        // Google Maps(衛星写真)を base layer として表示
        var gmapS = new OpenLayers.Layer.Google("Google SATELLITE", { type: google.maps.MapTypeId.SATELLITE, numZoomLevels:21 });
        map.addLayers([std_map, gmap, gmapS, gmapT]);

        // 中心座標を設定
        if (!map.getCenter()) { map.setCenter(new OpenLayers.LonLat(param.lon, param.lat).transform(proj_4326, proj_3857), param.zoom); }

        // kml 経路ファイルの読込み
        var kmlwayLayer = new OpenLayers.Layer.Vector('GPS経路データ', {
          projection: proj_4326, strategies: [new OpenLayers.Strategy.Fixed()],
          protocol: new OpenLayers.Protocol.HTTP({ url: param.url, format: new OpenLayers.Format.KML({extractStyles: true, extractAttributes: true, maxDepth: 2}) })
        });
        map.addLayer(kmlwayLayer);

        // kml ファイルの読込み
        var kmlLayer = new OpenLayers.Layer.Vector('GPSマーカーデータ', {
          projection: proj_4326, strategies: [new OpenLayers.Strategy.Fixed()],
          protocol: new OpenLayers.Protocol.HTTP({ url: param.url2, format: new OpenLayers.Format.KML({extractStyles: true, extractAttributes: true, maxDepth: 2}) })
        });
        map.addLayer(kmlLayer);

        // kml 内のマーカーをクリックした際の処理
        kmlLayer.events.on({ featureselected: onFeatureSelect, featureunselected: onFeatureUnselect });
        selectControl = new OpenLayers.Control.SelectFeature(kmlLayer);
        map.addControl(selectControl);
        selectControl.activate();

        // KeyboardDefaultsの設定:カーソルキー,+キー,-キーが使えるようになる
        map.addControl(new OpenLayers.Control.KeyboardDefaults());
        // Layer 切替スイッチ表示
        map.addControl(new OpenLayers.Control.LayerSwitcher());
        // スケールの表示:左下にあるスケール
        map.addControl(new OpenLayers.Control.ScaleLine({position: new OpenLayers.Pixel(100,map.getCurrentSize().h-40)}));
        // PanZoomBarの表示
        map.addControl(new OpenLayers.Control.PanZoomBar({position:new OpenLayers.Pixel(3,32), zoomWorldIcon:false, panIcons:true}));

        // 中心マーカーの表示
        funcCrosshairs(); // centercross ==1 なら表示される
        // タイトル画像の表示
        funcTitleImage();
        // アイコンシンボル画像の表示
        funcSymbolImage();
} // 初期化
// -------------------------------------------------------------------
// 中心マーカー:crosshairs cursor のクラス設定
OpenLayers.Control.CrosshairsCursor = OpenLayers.Class( OpenLayers.Control, {
  element : null, iconImageUrl: null, iconSize: new OpenLayers.Size(32,32), xyPos: new OpenLayers.Pixel(320,240),
  initialize: function(element) {
    OpenLayers.Control.prototype.initialize.apply(this, arguments);
    this.element = OpenLayers.Util.getElement(element);
  },
  draw: function() {
    OpenLayers.Control.prototype.draw.apply(this, arguments);
    var xy = this.xyPos.clone();
    var centerXYPos = new OpenLayers.Pixel( xy.x - (this.iconSize.w / 2), xy.y - (this.iconSize.h / 2));
    this.buttons = new Array();

    var uniqID = OpenLayers.Util.createUniqueID("OpenLayers.Control.Crosshairs_");
    this.div = OpenLayers.Util.createAlphaImageDiv(
      uniqID, centerXYPos, this.iconSize, this.iconImageUrl, "absolute");
    return this.div;
  },
  CLASS_NAME: "OpenLayers.Control.CrosshairsCursor"
});
// -------------------------------------------------------------------
/*中央の十字を書く関数(初期起動時と、ウインドウサイズが変更されると呼び出す。)*/
function funcCrosshairs(){
  if(map){//初期起動時のエラー回避処理
    if (centercross) { //チェックが入っている場合
      removeCrosshairs(); // いったん十字コントロール削除
      createCrosshairs(); // 十字コントロールの作成
    } else { return false; }
  }
}

/*中央の十字の表示・非表示を切り替える関数(チェックボックスで呼び出し)*/
function funcCrosshairs2() {
  if (!document.getElementById('centercross').checked) { removeCrosshairs(); } else { createCrosshairs(); }
}

/* 十字コントロールの作成 */
function createCrosshairs() {
  crosshairsCursorCtrl = new OpenLayers.Control.CrosshairsCursor({
    iconImageUrl:  "../../cj_map/crosshairs.png", iconSize: new OpenLayers.Size(32, 32), xyPos: new OpenLayers.Pixel( map.getCurrentSize().w/2, map.getCurrentSize().h/2 )
  });
  map.addControl( crosshairsCursorCtrl );
}

/* 十字コントロール削除 */
function removeCrosshairs(){
  if (crosshairsCursorCtrl) { map.removeControl(crosshairsCursorCtrl); }
  crosshairsCursorCtrl = null;
}
// -------------------------------------------------------------------
// 固定画像:fixedImage のクラス設定
OpenLayers.Control.FixedImage = OpenLayers.Class( OpenLayers.Control, {
  element : null, 
  imageUrl: null, 
  imageSize: new OpenLayers.Size(100,100), 
  xyPos: new OpenLayers.Pixel(0,0), // position of Left-Upper corner of the image
  initialize: function(element) {
    OpenLayers.Control.prototype.initialize.apply(this, arguments);  this.element = OpenLayers.Util.getElement(element);
  },
  draw: function() {
    OpenLayers.Control.prototype.draw.apply(this, arguments);
    var xy = this.xyPos.clone();
    var centerXYPos = new OpenLayers.Pixel( xy.x, xy.y);
    this.buttons = new Array();

    var uniqID = OpenLayers.Util.createUniqueID("OpenLayers.Control.ImageFixed_");
    this.div = OpenLayers.Util.createAlphaImageDiv(
      uniqID, centerXYPos, this.imageSize, this.imageUrl, "absolute");
    return this.div;
  },
  CLASS_NAME: "OpenLayers.Control.FixedImage"
});
// -------------------------------------------------------------------
/* タイトル画像を描く関数(初期起動時と、ウインドウサイズが変更されると呼び出す。)*/
function funcTitleImage(){
  if(map){//初期起動時のエラー回避処理
    if (titleimagedisplay) { //チェックが入っている場合
      removeTitleImage(); // いったん固定画像削除
      createTitleImage(); // 固定画像の作成
    } else { return false; }
  }
}

/* タイトル画像の表示・非表示を切り替える関数(チェックボックスで呼び出し)*/
function funcTitleImage2() {
  if (!document.getElementById('titleimagedisplay').checked) { removeTitleImage(); } else { createTitleImage(); }
}

/* タイトル画像の作成 */
function createTitleImage() {
  titleImageCtrl = new OpenLayers.Control.FixedImage({
    imageUrl: titleImageUrl, imageSize: title_image_size, xyPos: new OpenLayers.Pixel(50,0)
  });
  map.addControl( titleImageCtrl );
}

/* タイトル画像削除 */
function removeTitleImage(){
  if (titleImageCtrl) { map.removeControl(titleImageCtrl); }
  titleImageCtrl = null;
}
// -------------------------------------------------------------------
/* シンボル画像を描く関数(初期起動時と、ウインドウサイズが変更されると呼び出す。)*/
function funcSymbolImage(){
  if(map){//初期起動時のエラー回避処理
    if (symbolimagedisplay) { //チェックが入っている場合
      removeSymbolImage(); // いったん固定画像削除
      createSymbolImage(); // 固定画像の作成
    } else { return false; }
  }
}

/* シンボル画像の表示・非表示を切り替える関数(チェックボックスで呼び出し)*/
function funcSymbolImage2() {
  if (!document.getElementById('symbolimagedisplay').checked) { removeSymbolImage(); } else { createSymbolImage(); }
}

/* シンボル画像の作成 */
function createSymbolImage() {
  symbolImageCtrl = new OpenLayers.Control.FixedImage({
    imageUrl: symbolImageUrl, imageSize: symbol_image_size, 
    xyPos: new OpenLayers.Pixel( map.getCurrentSize().w - symbol_image_size.w, map.getCurrentSize().h - symbol_image_size.h -20 )
  });
  map.addControl( symbolImageCtrl );
}

/* シンボル画像削除 */
function removeSymbolImage(){
  if (symbolImageCtrl) { map.removeControl(symbolImageCtrl); }
  symbolImageCtrl = null;
}
// -------------------------------------------------------------------
// 地理院地図 (var std_map) の opacity(不透明度) を変える
function changeOpacity(opacity) {
  var newOpacity = ( parseFloat( OpenLayers.Util.getElement('opacity_control').value) + opacity ).toFixed(1); // 新しい opacity の値を求める
  newOpacity = Math.min( gMaxOpacity, Math.max( gMinOpacity, newOpacity) ); // 最大値と最小値の範囲を超えないように
  OpenLayers.Util.getElement('opacity_control').value = newOpacity; // opacity の数字の表示書き換え
  std_map.setOpacity(newOpacity); // 地理院地図の opacity の変更
}

function directSetOpacity(opacity) {
  std_map.setOpacity(opacity);
  OpenLayers.Util.getElement('opacity_control').value = opacity;
}
// -------------------------------------------------------------------
// kml 内のマーカーのコメントのpop up 処理
function onFeatureSelect(event) {
  var feature = event.feature;
  var content = '<h2>' + feature.attributes.name + '</h2>';
  if (feature.attributes.description) { content = content + feature.attributes.description; }

  var popup = new OpenLayers.Popup.FramedCloud('chicken',
    feature.geometry.getBounds().getCenterLonLat(), new OpenLayers.Size(200,200), content, null, true, onPopupClose
  );
  feature.popup = popup;
  map.addPopup(popup);
}

function onFeatureUnselect(event) {
  var popup = event.feature.popup;
  if (popup) { map.removePopup(popup); popup.destroy(); delete popup; }
}

function onPopupClose(event) {
  selectControl.unselectAll();
}
// -------------------------------------------------------------------
</script>
</head>

<body onload="init_map()">
<div id="map_canvas" style="width: 100%; height: 97%; position:absolute; top:25px; left:0px; font-size:200%;"></div>

<div style="font-size:85%">
    <a title="decrease opacity" href="javascript: directSetOpacity(1.0); ">地理院図</a> 
    <a title="decrease opacity" href="javascript: directSetOpacity(0.5);">地理院図+GMap</a> 
    <a title="decrease opacity" href="javascript: directSetOpacity(0.0);">GMap</a>  
<b>不透明度・0.2ずつ変更:
    <a title="decrease opacity" href="javascript: changeOpacity(-0.2);"><<</a>
    <input id="opacity_control" type="text" value="1.0" size="3" disabled="true">
    <a title="increase opacity" href="javascript: changeOpacity(0.2);">>></a></b>
          
    <input style="color:blue" onclick="removeCrosshairs();" type=button value="Center消去"> 
    <input style="color:red" onclick="funcCrosshairs();" type=button value="Center表示">  
    <input style="color:blue" onclick="removeTitleImage(); removeSymbolImage();" type=button value="タイトル凡例消去"> 
    <input style="color:red" onclick="funcTitleImage(); funcSymbolImage();" type=button value="タイトル凡例表示">  
右上の+マークで Google Map の <b>SATELLITE</b> や <b>TERRAIN</b> 選択可。
GPS 経路・マーカー:<font color="red">非表示</font>切替可
</div>

</body>
</html>
 ソースは色分けしてある。それぞれの部分について説明しよう。

(1) 灰色の部分は web の要素や,OpenLayers に関係のなさそうな JavaScript 等を示している。 説明は「その0:はじめに」を見て欲しい。

(2) 黒色の部分が OpenLayers のメインのパートである。 説明は「その1:OpenLayers を使って複数種類の Google Map を表示」や 「その2:OpenLayers を使って地理院地図を表示」を見て欲しい。

(3) 紫色の部分は,重ねた地図(ここでは地理院地図)の不透明度を変更して,2枚の地図の見え方を調節している部分である。 説明は「その4:不透明度を変えて2つの地図を重ねて表示」を見て欲しい。

(4) 赤色の部分は中心の十字マーカーに関連した部分である。 説明は「その3:中央にセンターマークを表示」を見て欲しい。

(5) 青色の部分は経路の KML ファイルに関連した部分である。 説明は「その5:KML ファイルで経路を表示」を見て欲しい。 ここで読み込ませている経路用の KML ファイルは,「その5:KML ファイルで経路を表示」で使った経路用の KML と同じである。

(6) 緑色の部分はマーカーの KML に関連した部分である。 説明は「その6:KML ファイルで経路とマーカーを表示」や 「その8:マーカーと経路を別々の KML ファイルで表示」を見て欲しい。 ここで読み込ませているマーカー用の KML ファイルは,「その8:マーカーと経路を別々の KML ファイルで表示」で使ったマーカー用の KML ファイルと同じである。

(7) 最後に,水色の部分はタイトル画像に関連した部分であり, オレンジ色の部分はマーカーの凡例に関連した部分である。 これらはこれまで特別に説明はしてないので,ここで少し説明しておこう。 これらの部分は,地図上に固定の画像を表示させている部分である。 ここでは,地図のタイトルとマーカー画像の凡例を示す画像をそれぞれ左上と右下に表示させている。 基本的な考え方は中央に十字マーカーを描画するのと同じなので, 説明としては「その3:中央にセンターマークを表示」に書かれているのと同じことをしている。 もしかしたら十字マーカーと共通で使える部分もあるかもしれないが,一応今回は全く別に用意してある。

 タイトル画像とマーカーの凡例は,コメントに「// 固定画像:fixedImage のクラス設定」と書かれた部分でまず固定画像表示用のクラスを設定している。 具体的にはこのクラスの変数が持つべき引数などについて設定を記述している。 その後で,タイトル画像とマーカー凡例それぞれを描画するための関数を定義している。 タイトル画像に関連して,「function funcTitleImage()」,「function funcTitleImage2()」,「function createTitleImage()」,「function removeTitleImage()」,の4つを定義している。 これらはそれぞれ,タイトル画像描画時に呼ばれる関数,タイトル画像の表示・非表示を切り替える関数,タイトル画像の具体的な描画処理,タイトル画像の抹消処理,を行っている。 マーカー凡例についても同じく4つの関数が定義されている。 これらの関数は,初期化のルーチンの中で描画関数が呼ばれている。 また,最後の方に記載がある web ページの中で,タイトル画像と凡例の消去と表示のボタンが定義されていて,その中でも呼ばれている。

 「その9」のサンプルを具体的な web ページとして用意したので,具体的な表示を見てみて欲しい。
(ちなみにサンプルページはアクセスログを取るルーチンを組み込んでいます)

 最初の方にも書いたが,今回の OpenLayers 2.13.1 を使った地理院地図に関するページは今回が最終回である。 ここに記載した OpenLayers は,現在 OpenLayers 3 が作られつつあり,2.13.1 は古いバージョンであるが, まだ OpenLayers 2.13.1 もしばらくは使えると思うので,ここでの記載が皆さんの役に立つことを祈っている。

0 件のコメント: