チュートリアル10

提供: svg2wiki
(版間での差分)
移動: 案内, 検索
(rasterMesh.svg)
(rasterMesh.html)
56行: 56行:
 
**rect.setAttribute("content",meshNumb+","+meshs[meshNumb].join(" "));
 
**rect.setAttribute("content",meshNumb+","+meshs[meshNumb].join(" "));
 
***meshs[meshNumb] 市区町村コード
 
***meshs[meshNumb] 市区町村コード
 +
 +
<pre>
 +
<!doctype html>
 +
<html>
 +
<head>
 +
<title>Geoid Height Calc WebApp</title>
 +
<meta charset="utf-8"></meta>
 +
</head>
 +
<script>
 +
// Description:
 +
// MeshData Visualizer.
 +
//
 +
// History:
 +
// 2022/02/14 : 1st rev.
 +
 +
// 読み込んだASCIIデータを保持するグローバル変数
 +
var geoidGrid=[];
 +
var dataProps;
 +
 +
onload = async function(){
 +
// メッシュデータを読み込みグローバル変数に保存
 +
await buildData();
 +
// 読み込んだデータからdataURIとしてビットイメージを生成
 +
var duri = buildImage(geoidGrid,document.getElementById("geoidCanvas"));
 +
// 生成した画像の地理的な範囲
 +
// 画像になると、グリッドの点は画像のピクセルの中心となることに注意!
 +
var imageGeoArea={
 +
lng0: dataProps.glomn - dataProps.dglo/2,
 +
lat0: dataProps.glamn - dataProps.dgla/2,
 +
lngSpan: dataProps.nlo * dataProps.dglo,
 +
latSpan: dataProps.nla * dataProps.dgla
 +
}
 +
if ( typeof(svgMap)=="object" ){
 +
buildSvgImage(duri,imageGeoArea); // SVGコンテンツを生成
 +
svgMap.refreshScreen();
 +
}
 +
}
 +
 +
async function buildData(){
 +
var gtxt = await loadText("gsigeo2011_ver2_1.asc");
 +
 +
gtxt = gtxt.split("\n");
 +
 +
dataProps = getHeader(gtxt[0]);
 +
var gx=0, gy=0;
 +
var geoidGridLine=[];
 +
for ( var i = 1 ; i < gtxt.length ; i++){
 +
var na = getNumberArray(gtxt[i]);
 +
gx += na.length;
 +
geoidGridLine = geoidGridLine.concat(na);
 +
if ( gx >= dataProps.nlo ){
 +
geoidGrid.push(geoidGridLine);
 +
geoidGridLine=[];
 +
gx=0;
 +
}
 +
}
 +
}
 +
 +
function buildImage(geoidGrid, canvas){
 +
//
 +
canvas.width=dataProps.nlo;
 +
canvas.height=dataProps.nla;
 +
var context = canvas.getContext('2d');
 +
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
 +
var pixels = imageData.data;
 +
for ( var py = 0 ; py < dataProps.nla ; py++ ){
 +
var dy = dataProps.nla - 1 - py
 +
for ( var px = 0 ; px < dataProps.nlo ; px++ ){
 +
var base = (dy * dataProps.nlo + px) * 4;
 +
if ( geoidGrid[py][px]!=999){
 +
 +
var hue = (1-(geoidGrid[py][px]-dataProps.minVal)/(dataProps.maxVal-dataProps.minVal))*270;
 +
var rgb = HSVtoRGB(hue,255,255);
 +
 +
pixels[base + 0] = rgb.r;  // Red
 +
pixels[base + 1] = rgb.g;  // Green
 +
pixels[base + 2] = rgb.b;  // Blue
 +
pixels[base + 3] = 255;  // Alpha
 +
}
 +
}
 +
}
 +
context.putImageData(imageData, 0, 0);
 +
 +
var duri = canvas.toDataURL('image/png');
 +
return ( duri );
 +
}
 +
 +
function getHeader(line){
 +
var datas = parseLine(line);
 +
return {
 +
glamn:Number(datas[0]),
 +
glomn:Number(datas[1]),
 +
dgla:Number(datas[2]),
 +
dglo:Number(datas[3]),
 +
nla:Number(datas[4]),
 +
nlo:Number(datas[5]),
 +
ikind:Number(datas[6]),
 +
vern:datas[7],
 +
minVal:9e99,
 +
maxVal:-9e99
 +
}
 +
}
 +
 +
function getNumberArray(line){
 +
var ans = [];
 +
var lineArray = parseLine( line );
 +
for ( var col of lineArray){
 +
var val = Number(col);
 +
if ( val != 999){
 +
if ( val > dataProps.maxVal){
 +
dataProps.maxVal=val;
 +
}
 +
if ( val < dataProps.minVal){
 +
dataProps.minVal=val;
 +
}
 +
}
 +
ans.push(val);
 +
}
 +
return ( ans );
 +
}
 +
 +
function parseLine(line){
 +
var ans = line.trim().split(/\s+/)
 +
return (ans);
 +
}
 +
 +
 +
async function loadText(url){ // テキストデータをfetchで読み込む
 +
messageDiv.innerText="ジオイド高データを読み込み中です";
 +
var response = await fetch(url);
 +
var txt = await response.text();
 +
messageDiv.innerText="";
 +
return ( txt );
 +
}
 +
 +
function HSVtoRGB (h, s, v) { // from http://d.hatena.ne.jp/ja9/20100903/1283504341
 +
var r, g, b; // 0..255
 +
while (h < 0) {
 +
h += 360;
 +
}
 +
h = h % 360;
 +
 +
// 特別な場合 saturation = 0
 +
if (s == 0) {
 +
// → RGB は V に等しい
 +
v = Math.round(v);
 +
return {'r': v, 'g': v, 'b': v};
 +
}
 +
s = s / 255;
 +
 +
var i = Math.floor(h / 60) % 6,
 +
f = (h / 60) - i,
 +
p = v * (1 - s),
 +
q = v * (1 - f * s),
 +
t = v * (1 - (1 - f) * s);
 +
 +
switch (i) {
 +
case 0 :
 +
r = v;  g = t;  b = p;  break;
 +
case 1 :
 +
r = q;  g = v;  b = p;  break;
 +
case 2 :
 +
r = p;  g = v;  b = t;  break;
 +
case 3 :
 +
r = p;  g = q;  b = v;  break;
 +
case 4 :
 +
r = t;  g = p;  b = v;  break;
 +
case 5 :
 +
r = v;  g = p;  b = q;  break;
 +
}
 +
return {'r': Math.round(r), 'g': Math.round(g), 'b': Math.round(b)};
 +
}
 +
 +
 +
// 以下はSVGMapレイヤーとして動かしたときに有効になる関数
 +
var CRSad = 100; // svgmapコンテンツのCRSきめうち・・
 +
function  buildSvgImage(imageDataUri,imageParam){
 +
// dataURLを受け取って、SVGMapコンテンツに画像を張り付ける
 +
var rct = svgImage.createElement("image");
 +
rct.setAttribute("x", imageParam.lng0 * CRSad);
 +
rct.setAttribute("y", -(imageParam.lat0 + imageParam.latSpan) * CRSad);
 +
rct.setAttribute("width", imageParam.lngSpan * CRSad);
 +
rct.setAttribute("height", imageParam.latSpan * CRSad);
 +
rct.setAttribute("xlink:href",imageDataUri);
 +
rct.setAttribute("style","image-rendering:pixelated"); // メッシュデータなので拡大次画像のピクセルをくっきりさせる
 +
var root = svgImage.documentElement;
 +
root.appendChild(rct);
 +
}
 +
 +
</script>
 +
<body>
 +
<h3>メッシュデータ可視化(ビットイメージ化)</h3>
 +
<p><a href="https://fgd.gsi.go.jp/download/geoid.php" target="_blank">地理院のジオイド・モデル「日本のジオイド2011」(Ver.2.1)の提供</a>のASCII版に同梱されているデータをビットイメージ化されたメッシュデータとして可視化します。
 +
</p>
 +
<div id="messageDiv" style="color:red"></div>
 +
<div>
 +
<canvas id="geoidCanvas" style="display:none"></canvas>
 +
</body>
 +
</html>
 +
</pre>

2022年2月15日 (火) 05:51時点における版

目次

チュートリアル10 WebApp Layer WebApp Layer メッシュデータのビットイメージ化

メッシュデータ(グリッドデータ)はラスターデータとも呼ばれるように、Webコンテンツとして一般的に使われるビットイメージデータ形式(PNGやJPEGなど)とほぼ同等の形式です。そこでメッシュデータを動的にビットイメージコンテンツ(PNG形式)化し、地図画面上に表示するWebAppを構築してみます。性能面でのメリットがあります。

特徴的なコードはレイヤーに紐付いたwebAppにあります。




使用するデータ

地理院がこちらのページで公開するジオイド高データ(TEXTデータ)を使用します。

実際に使用するデータ

このデータの詳細な仕様は上記サイトで配布されているパッケージ同梱文書(asc取扱説明書.pdf)に記載されていますが、基本的にはテキストのRaster形式です。

データ形式としては、カンマ区切りでなく空白文字区切り 一つのRaw(桁)が1行で終結せず、255文字で改行される点が注意点です

データの内容としては、グリッドデータの原点の定義と、それをビットイメージ画像として可視化したときの原点との違いに注意が必要です。(下記2点)

  • Y(緯度)軸の向きが逆のため、元のラスターデータの原点は南端、ビットイメージの原点は上端、
  • ラスターデータの原点は、それをビットイメージとして可視化したときのピクセルの中心位置なのに対し、ビットイメージを配置するときの原点はピクセルの左上隅
  • Raster.png 説明図svg

mesh3.html

これまでと特に変わったところはありません。

Container.svg

これまでと特に変わったところはありません。

rasterMesh.svg

  • WebAppが(下記rasterMesh.html)が紐付けられた空白のコンテンツです。
  • 表示とともにwebAppのウィンドが出現するように指定しています。
  • これまでと特に変わったところはありません。
<?xml version="1.0" encoding="UTF-8"?>
<svg  xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-42.8202042942663, -49.9999999999999, 513.842451531196, 600" xmlns:go="http://purl.org/svgmap/profile"  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" property="Local government codes" data-controller="rasterMesh.html#exec=appearOnLayerLoad">

<globalCoordinateSystem srsName="http://purl.org/crs/84" transform="matrix(100,0,0,-100,0,0)" />
</svg>

rasterMesh.html

  • onload=async function()
    • svgMap.setShowPoiProperty( customShowPoiProperty, layerID);
      • 紐付いたレイヤーのオブジェクトをヒットしたときに出現する処理に独自のコールバック関数(customShowPoiProperty)に指定する
      • customShowPoiProperty
        • ヒットしたオブジェクトのcontent属性にある市区町村コードをKeyにしてlgDictionaryを辞書引き、自治体名を求める
          • 一つのメッシュに複数の自治体が属しているケースがある点に注意
        • svgMap.showModal(html,400,180); 用意したhtmlをSVGMapフレームワークのモーダルダイアログに渡す
  • async function loadLGdictionary(){ // 自治体名辞書を作る
    • lgDictionary={};//市区町村コードをKeyとした自治体名辞書
  • function buildMeshTileSvg(meshs, sourceID){
    • rect.setAttribute("content",meshNumb+","+meshs[meshNumb].join(" "));
      • meshs[meshNumb] 市区町村コード
<!doctype html>
<html>
<head>
<title>Geoid Height Calc WebApp</title>
<meta charset="utf-8"></meta>
</head>
<script>
// Description:
// MeshData Visualizer.
// 
// History:
// 2022/02/14 : 1st rev.

// 読み込んだASCIIデータを保持するグローバル変数
var geoidGrid=[];
var dataProps;

onload = async function(){
	// メッシュデータを読み込みグローバル変数に保存
	await buildData();
	// 読み込んだデータからdataURIとしてビットイメージを生成
	var duri = buildImage(geoidGrid,document.getElementById("geoidCanvas")); 
	// 生成した画像の地理的な範囲
	// 画像になると、グリッドの点は画像のピクセルの中心となることに注意!
	var imageGeoArea={
		lng0: dataProps.glomn - dataProps.dglo/2,
		lat0: dataProps.glamn - dataProps.dgla/2,
		lngSpan: dataProps.nlo * dataProps.dglo,
		latSpan: dataProps.nla * dataProps.dgla
	}
	if ( typeof(svgMap)=="object" ){
		buildSvgImage(duri,imageGeoArea); // SVGコンテンツを生成
		svgMap.refreshScreen();
	}
}

async function buildData(){
	var gtxt = await loadText("gsigeo2011_ver2_1.asc");
	
	gtxt = gtxt.split("\n");
	
	dataProps = getHeader(gtxt[0]);
	var gx=0, gy=0;
	var geoidGridLine=[];
	for ( var i = 1 ; i < gtxt.length ; i++){
		var na = getNumberArray(gtxt[i]);
		gx += na.length;
		geoidGridLine = geoidGridLine.concat(na);
		if ( gx >= dataProps.nlo ){
			geoidGrid.push(geoidGridLine);
			geoidGridLine=[];
			gx=0;
		}
	}
}

function buildImage(geoidGrid, canvas){
	//
	canvas.width=dataProps.nlo;
	canvas.height=dataProps.nla;
	var context = canvas.getContext('2d');
	var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
	var pixels = imageData.data; 
	for ( var py = 0 ; py < dataProps.nla ; py++ ){
		var dy = dataProps.nla - 1 - py
		for ( var px = 0 ; px < dataProps.nlo ; px++ ){
			var base = (dy * dataProps.nlo + px) * 4;
			if ( geoidGrid[py][px]!=999){
				
				var hue = (1-(geoidGrid[py][px]-dataProps.minVal)/(dataProps.maxVal-dataProps.minVal))*270;
				var rgb = HSVtoRGB(hue,255,255);
				
				pixels[base + 0] = rgb.r;  // Red
				pixels[base + 1] = rgb.g;  // Green
				pixels[base + 2] = rgb.b;  // Blue
				pixels[base + 3] = 255;  // Alpha
			}
		}
	}
	context.putImageData(imageData, 0, 0);
	
	var duri = canvas.toDataURL('image/png');
	return ( duri );
}

function getHeader(line){
	var datas = parseLine(line);
	return {
		glamn:Number(datas[0]),
		glomn:Number(datas[1]),
		dgla:Number(datas[2]),
		dglo:Number(datas[3]),
		nla:Number(datas[4]),
		nlo:Number(datas[5]),
		ikind:Number(datas[6]),
		vern:datas[7],
		minVal:9e99,
		maxVal:-9e99
	}
}

function getNumberArray(line){
	var ans = [];
	var lineArray = parseLine( line );
	for ( var col of lineArray){
		var val = Number(col);
		if ( val != 999){
			if ( val > dataProps.maxVal){
				dataProps.maxVal=val;
			}
			if ( val < dataProps.minVal){
				dataProps.minVal=val;
			}
		}
		ans.push(val);
	}
	return ( ans );
}

function parseLine(line){
	var ans = line.trim().split(/\s+/)
	return (ans);
}


async function loadText(url){ // テキストデータをfetchで読み込む
	messageDiv.innerText="ジオイド高データを読み込み中です";
	var response = await fetch(url);
	var txt = await response.text();
	messageDiv.innerText="";
	return ( txt );
}

function HSVtoRGB (h, s, v) { // from http://d.hatena.ne.jp/ja9/20100903/1283504341
	var r, g, b; // 0..255
	while (h < 0) {
		h += 360;
	}
	h = h % 360;
	
	// 特別な場合 saturation = 0
	if (s == 0) {
		// → RGB は V に等しい
		v = Math.round(v);
		return {'r': v, 'g': v, 'b': v};
	}
	s = s / 255;
	
	var i = Math.floor(h / 60) % 6,
	f = (h / 60) - i,
	p = v * (1 - s),
	q = v * (1 - f * s),
	t = v * (1 - (1 - f) * s);

	switch (i) {
	case 0 :
		r = v;  g = t;  b = p;  break;
	case 1 :
		r = q;  g = v;  b = p;  break;
	case 2 :
		r = p;  g = v;  b = t;  break;
	case 3 :
		r = p;  g = q;  b = v;  break;
	case 4 :
		r = t;  g = p;  b = v;  break;
	case 5 :
		r = v;  g = p;  b = q;  break;
	}
	return {'r': Math.round(r), 'g': Math.round(g), 'b': Math.round(b)};
}


// 以下はSVGMapレイヤーとして動かしたときに有効になる関数
var CRSad = 100; // svgmapコンテンツのCRSきめうち・・
function  buildSvgImage(imageDataUri,imageParam){
	// dataURLを受け取って、SVGMapコンテンツに画像を張り付ける
	var rct = svgImage.createElement("image");
	rct.setAttribute("x", imageParam.lng0 * CRSad);
	rct.setAttribute("y", -(imageParam.lat0 + imageParam.latSpan) * CRSad);
	rct.setAttribute("width", imageParam.lngSpan * CRSad);
	rct.setAttribute("height", imageParam.latSpan * CRSad);
	rct.setAttribute("xlink:href",imageDataUri);
	rct.setAttribute("style","image-rendering:pixelated"); // メッシュデータなので拡大次画像のピクセルをくっきりさせる
	var root = svgImage.documentElement;
	root.appendChild(rct);
}

</script>
<body>
<h3>メッシュデータ可視化(ビットイメージ化)</h3>
<p><a href="https://fgd.gsi.go.jp/download/geoid.php" target="_blank">地理院のジオイド・モデル「日本のジオイド2011」(Ver.2.1)の提供</a>のASCII版に同梱されているデータをビットイメージ化されたメッシュデータとして可視化します。
</p>
<div id="messageDiv" style="color:red"></div>
<div>
<canvas id="geoidCanvas" style="display:none"></canvas>
</body>
</html>
個人用ツール
名前空間

変種
操作
案内
ツール
Translate