ShapefileをOpenLayersで表示する。[2]

ShapefileをOpenLayersで表示する。[その2]

ShapefileをOpenLayersで表示する。[その1] に続いて、Shapefileを直接読み込んで、OpenLayer上で表示してみます。
元ネタは、shapefile-jsで公開されているJavaScriptを使いました。

開発環境は、Windows 7 32bit,Aptana Studio 3.4
Firefox 20.0とGoogle Chromeで確認しました。IE9でも表示できるようです。

必要なJavaScript

shapefile-jsからmasterのZIPをdownloadして、unzipします。 とりあえずDesktopでも大丈夫です。
後は、OpenLayersをここから2.12をdownloadして解凍しておきます。

Folder,Fileの構成は
blog.godo-tys.jp_wp-content_gallery_shapefile_2_image01.jpg
な感じです。

kanagawa folderに表示させたいShapefile一式をcopy、その際にshp,shx、dbfの3つのファイルが必要になります。
utf8 folderには、あらかじめshapefileからGeoJSONに変換したをjsonデータを入れてあります。encodeはutf-8です。

Shapefileを表示してみる。

exampleのファイルを編集します。
HTML5で作成します。file名は、ol_simple.htmlol_simple.jsです。
codeは簡単です。元のcodeを参考にして若干手を加えています。

<html>
	<head>
		<title>Kanagawa Pref. Japan - Javascript Shapefile and DBF Loader</title>
		<script type="text/javascript" src="lib/binaryajax.js"></script>
		<script type="text/javascript" src="src/binarywrapper.js"></script>
		<script type="text/javascript" src="src/shapefile.js"></script>
		<script type="text/javascript" src="src/dbf.js"></script>
		<script type="text/javascript" src="src/ol_shapefile.js"></script>
		<script type="text/javascript" src="lib/OpenLayers/OpenLayers.js"></script>
		<script type="text/javascript" src="ol_simple.js"></script>
		<link rel="stylesheet" href="lib/OpenLayers/theme/default/style.css" type="text/css" />
 
		<!--[if IE]>
<script src="lib/excanvas.js"></script><![endif]-->
		<style type="text/css">
			body {
				background-color: #eeeeee;
				color: #000000;
				font: 12px sans-serif;
				margin: 20px;
			}
			#map {
				width: 600px;
				height: 480px;
				margin: 0;
				padding: 0;
				border: 0;
				background-color: #9dc3e0;
			}
			a img {
				border: 0;
			}
			.olControlMousePosition {
			    font-size: 12pt;
			    background-color: white
			}
		</style>
	</head>
	<body>
		<h2 id="title">OpenstreetmapにShape fileをOverlay</h2>
		<div id="map" name="map"></div>
		<div id="docs">
			<p>
				OSMと神奈川県のShape fileデータを表示します。
			</p>
			<p>
				SHPデータは[EPSG:4326],dbfファイルはShift_JIS
				<br>
				日本語2バイト文字は化けている
			</p>
			<p>
				See <a href="http://github.com/RandomEtc/shapefile-js">http://github.com/RandomEtc/shapefile-js</a> for more details.
			</p>
		</div>
	</body>
</html>

次にol_simple.jsを編集します。

// all the interaction stuff is copied almost verbatim from
// http://www.openlayers.org/dev/examples/dynamic-text-layer.html
 
window.onload = function() {
	map = new OpenLayers.Map('map');
 
	var osm = new OpenLayers.Layer.OSM("OpenStreetMap");
 
	var shpLayer = new OpenLayers.Layer.Vector("shpLayer",{
		projection : new OpenLayers.Projection('EPSG:4326')
	});
	map.addLayers([osm, shpLayer]);
	map.setCenter(new OpenLayers.LonLat(139.4, 35.4).
		transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:3857")),
		9
	);
 
	// Interaction; not needed for initial display.
	selectControl = new OpenLayers.Control.SelectFeature(shpLayer);
	map.addControl(selectControl);
	selectControl.activate();
	shpLayer.events.on({
		'featureselected' : onFeatureSelect,
		'featureunselected' : onFeatureUnselect
	});
	map.addControl(new OpenLayers.Control.LayerSwitcher());
	map.addControl(new OpenLayers.Control.Attribution());
	map.addControl(new OpenLayers.Control.ScaleLine());
	map.addControl(new OpenLayers.Control.MousePosition({
			displayProjection: new OpenLayers.Projection("EPSG:4326")
		})
	);
 
	// load the shapefile
	var theUrl = 'kanagawa/c14_region';
	getOpenLayersFeatures(theUrl, function(fs) {
		// reproject features
		// this is ordinarily done by the format object, but since we're adding features manually we have to do it.
		var fsLen = fs.length;
		var inProj = new OpenLayers.Projection('EPSG:4326');
		var outProj = new OpenLayers.Projection('EPSG:3857');
		for (var i = 0; i < fsLen; i++) {
			fs[i].geometry = fs[i].geometry.transform(inProj, outProj);
		}
		shpLayer.addFeatures(fs);
	});
}
// Needed only for interaction, not for the display.
function onPopupClose(evt) {
	// 'this' is the popup.
	var feature = this.feature;
	if (feature.layer) {// The feature is not destroyed
		selectControl.unselect(feature);
	} else {// After "moveend" or "refresh" events on POIs layer all
		//     features have been destroyed by the Strategy.BBOX
		this.destroy();
	}
}
 
function onFeatureSelect(evt) {
	feature = evt.feature;
	var table = '<table>';
	for (var attr in feature.attributes.values) {
		table += '<tr><td>' + attr + '</td><td>' + feature.attributes.values[attr] + '</td></tr>';
	}
	table += '</table>';
	popup = new OpenLayers.Popup.FramedCloud("featurePopup", feature.geometry.getBounds().getCenterLonLat(), new OpenLayers.Size(100, 100), table, null, true, onPopupClose);
	feature.popup = popup;
	popup.feature = feature;
	map.addPopup(popup, true);
}
 
function onFeatureUnselect(evt) {
	feature = evt.feature;
	if (feature.popup) {
		popup.feature = null;
		map.removePopup(feature.popup);
		feature.popup.destroy();
		feature.popup = null;
	}
}

要するに、shpLayerというvector layerを作成して、Shapefileを読み込んで、JSONに変換して、shpLayer.addFeaturesを作成すると言うことです。

libとsourceのcodeは難しくないので、解読することができます。

では、kanagawa folderからshapefileを読み込んでみます。

FireFoxで実行させると、
blog.godo-tys.jp_wp-content_gallery_shapefile_2_image02.jpg

な感じで、Shapefileが表示されます。Good Job!!ですね。
ここでは、神奈川県の市区町村の行政界を表示しています。

また、GeoJSONに変換して表示されたfeatureをクリックすると属性値が表示されます。
blog.godo-tys.jp_wp-content_gallery_shapefile_2_image03.jpg

な感じです。

が。。。。 みての通り、nameが日本語表示されません。
ShapefileをOpenLayersで表示する。[その1] と同じで、どうやっても、属性データが文字化けしてしまいます。
これは、2byte codeで表現される日本語が化けるのです。

utf8変換のjsを利用したり、encodingを試したのですが。。。
問題点は、このbainaryをstream.jsで呼び出す際に1byteごと読み出して、code変換しているため文字化けすることはわかったのですが。Firebugで追っかけてもみました。
いかんせん、力量不足。。。

電子国土とGoogle mapとのOverlayも
blog.godo-tys.jp_wp-content_gallery_shapefile_2_image04.jpg

な感じでうまくいきます。 属性だけが。。。。

文字化けの問題点と修正

またもや、2byteの日本語の壁にぶち当たりました。
変更すべき点は、

  1. binary dataをdbfのfield.lengthで一度に呼び込む
  2. 1byteか2byteかの判断をする。
  3. 2byteならば、encodingでutf8へ変換する。

これでいけるんじゃない? だからそのcodeは?

何か良い知恵はないでしょうか? ぜひお知恵を拝借させてください。

次回のお題

shapefileが読めなくてもいいさ。
GeoJSONでやれば。
ということで、ExtJS3.4とGeoExt1.1について、健忘禄をかねて少し書いてみます。

おまけ

電子国土とGoogle mapとOpenstreetmap上にGeoJSONを読み込んで表示させるcode

<!DOCTYPE html>
<html lang="ja">
	<head>
		<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
		<title>電子国土にGeoJSON fileをオーバーレイ表示する</title>
		<script type="text/javascript" src="lib/OpenLayers/OpenLayers.js" charset="UTF-8"></script>
		<script type="text/javascript" src="lib/v4/webtis/webtis_v4.js" charset="UTF-8"></script>
		<link rel="stylesheet" href="lib/v4/css/webtis.css" type="text/css">
		<script src="http://maps.google.com/maps/api/js?v=3.9&amp;sensor=false"></script>
		<script type="text/javascript">
			//<!--
			/*グローバル変数の宣言ここから*/
			//地図インスタンス
			var map = null;
 
			//初期の経度
			var initCX = 139.4;
 
			//初期の緯度
			var initCY = 35.4;
 
			//初期のズームレベル
			//※ここで設定するズームレベルはデータセットの最小ズームレベルが0になる
			//※デフォルトデータセットでは「ズームレベル5」が0になる
			var initZoomLv = 4;
 
			//真球メルカトル投影(電子国土WebシステムVer.4もこれに準拠)を定義
			var projection3857 = new OpenLayers.Projection("EPSG:3857");
 
			//等経緯度投影を定義
			var projection4326 = new OpenLayers.Projection("EPSG:4326");
			/*グローバル変数の宣言ここまで*/
 
			/*地図の初期表示設定ここから*/
			function init() {
				//真球メルカトル投影のときの最大範囲(単位はm)
				var maxExtent = new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508);
 
				//真球メルカトル投影のときの最大範囲に範囲を制限
				var restrictedExtent = maxExtent.clone();
 
				//真球メルカトル投影のときの最大解像度
				var maxResolution = 156543.0339;
 
				//地図表示画面のオプション設定
				var options = {
					//「controls」を設定することで、デフォルトのコントロールを破棄してコントロールを再設定
					controls : [
					//地図マウスイベントのハンドル設定。
					new OpenLayers.Control.Navigation({
						mouseWheelOptions : {
							interval : 100
						}
					}),
 
					//左上のパンズームバーを設定
					new OpenLayers.Control.PanZoomBar(),
 
					//キーボードをデフォルトに設定
					new OpenLayers.Control.KeyboardDefaults(),
 
					//国土地理院著作表示
					//※OpenLayrsサイトを作るときは必ずこれを書くこと
					//new OpenLayers.Control.Attribution()
 
					// ベースレイヤー切り替え
					new OpenLayers.Control.LayerSwitcher(),
 
					// マウス移動時に緯度経度を表示
					new OpenLayers.Control.MousePosition()],
 
					//背景地図の地理座標系
					projection : projection3857,
 
					//表示の地理座標系
					displayProjection : projection4326,
 
					//背景地図の単位
					units : "m",
 
					//背景地図の最大解像度
					maxResolution : maxResolution,
 
					//背景地図の最大範囲
					maxExtent : maxExtent,
 
					//背景地図の表示制限範囲
					restrictedExtent : restrictedExtent
				};
 
				//OpenLayers APIのMapクラスからインスタンスを作成
				map = new OpenLayers.Map('map', options);
 
				//スケールバーコントロール表示(最大ピクセル150、下段単位無、EPSG:3857)
				map.addControl(new OpenLayers.Control.ScaleLine({
					maxWidth : 150,
					bottomOutUnits : "",
					bottomInUnits : "",
					geodesic : true
				}));
 
				//電子国土WebシステムVer.4背景地図レイヤーインスタンスを作成。データセットは未指定で、デフォルトデータセットを利用
				var webtisMap = new webtis.Layer.BaseMap("電子国土");
 
				//背景地図レイヤーをMapに追加
				map.addLayer(webtisMap);
 
				//背景地図レイヤーをGooglemap道路地図を追加
				var gmaplayerRoad = new OpenLayers.Layer.Google('道路地図', {
					numZoomLevels : 20
				}, {
					visibility : true
				});
				map.addLayer(gmaplayerRoad);
 
				//背景地図レイヤーをGooglemap衛星写真を追加
				var gmaplayerHybrid = new OpenLayers.Layer.Google('衛星写真', {
					type : google.maps.MapTypeId.HYBRID
				}, {
					numZoomLevels : 20
				}, {
					visibility : true
				});
				map.addLayer(gmaplayerHybrid);
 
				//Openstreetmapの追加
				var osm = new OpenLayers.Layer.OSM('OSM');
				map.addLayer(osm);
 
				//ShapeLayer用スタイル設定
				var shpstyles = new OpenLayers.StyleMap({
					"default" : {//通常状態
						strokeWidth : 1,
						strokeColor : "blue",
						fillColor : "blue",
						fillOpacity : 0.3
					}
				});
 
				//行政界ShapeLayerの追加
				/*var shpRegionLayer = new OpenLayers.Layer.Vector('行政界', {
					projection : projection4326,
					styleMap : shpstyles
				});
				map.addLayer(shpRegionLayer);*/
 
				var geojsonlayer = new OpenLayers.Layer.Vector("行政界", {
					strategies : [new OpenLayers.Strategy.Fixed()],
					protocol : new OpenLayers.Protocol.HTTP({
						url : "utf8/c14_road_utf.json",
						format : new OpenLayers.Format.GeoJSON()
					}),
					projection: projection4326
					//projection: projection3857
				});
				map.addLayer(geojsonlayer);
 
				// Interaction; not needed for initial display.
				selectControl = new OpenLayers.Control.SelectFeature(geojsonlayer);
				map.addControl(selectControl);
				selectControl.activate();
				geojsonlayer.events.on({
					'featureselected' : onFeatureSelect,
					'featureunselected' : onFeatureUnselect
				});
 
				//初期の中心座標を指定(経緯度で入力して、内部的に真球メルカトル座標に変換して表示)
				map.setCenter(new OpenLayers.LonLat(initCX, initCY).transform(projection4326, projection3857), initZoomLv);
 
				//神奈川県の市町村区界shape fileを読み込む
				/*var theRegionUrl = 'kanagawa/c14_region';
				getOpenLayersFeatures(theRegionUrl, function(fs1) {
					var fs1Len = fs1.length;
					var inProj = projection4326;
					var outProj = projection3857;
					for (var i = 0; i < fs1Len; i++) {
						fs1[i].geometry = fs1[i].geometry.transform(inProj, outProj);
					}
					shpRegionLayer.addFeatures(fs1);
				});*/
 
			}
 
			// Needed only for interaction, not for the display.
			function onPopupClose(evt) {
				// 'this' is the popup.
				var feature = this.feature;
				if (feature.layer) {// The feature is not destroyed
					selectControl.unselect(feature);
				} else {// After "moveend" or "refresh" events on POIs layer all
					//     features have been destroyed by the Strategy.BBOX
					this.destroy();
				}
			}
 
			function onFeatureSelect(evt) {
				feature = evt.feature;
				var table = '<table>
';
				table += '<p>属性値</p>';
				for (var attr in feature.attributes) {
					table += '<tr><td>' + attr + '</td><td>' + feature.attributes[attr] + '</td></tr>';
				}
				//table += '<tr><td>' + 'name:' + '</td><td>' + feature.attributes.name + '</td></tr>';
				table += '</table>';
				popup = new OpenLayers.Popup.FramedCloud("featurePopup", feature.geometry.getBounds().getCenterLonLat(), new OpenLayers.Size(100, 100), table, null, true, onPopupClose);
				feature.popup = popup;
				popup.feature = feature;
				map.addPopup(popup, true);
			}
 
			function onFeatureUnselect(evt) {
				feature = evt.feature;
				if (feature.popup) {
					popup.feature = null;
					map.removePopup(feature.popup);
					feature.popup.destroy();
					feature.popup = null;
				}
			}
 
			/*地図の初期表示設定ここまで*/
			//-->
		</script>
	</head>
	<body onload="init();">
		<h2 id="title">電子国土にShape fileをOverlay</h2>
		<div id="map" name="map" style="width:600px;height:480px;"></div>
		<div id="docs">
			<p>
				電子国土と神奈川県のGeoJSON fileデータを表示します。
			</p>
			<p>
				GeoJSONデータは[EPSG:4326],UTF-8
			</p>
		</div>
	</body>
</html>

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 

WP-SpamFree by Pole Position Marketing

Social Widgets powered by AB-WebLog.com.