チュートリアル5
提供: svg2wiki
(版間での差分)
(→dynamicOSM_r10.svg) |
(→dynamicOSM_r11.svg) |
||
67行: | 67行: | ||
* SVGコンテンツのドキュメント要素(svg要素)のdata-controller属性でウェブアプリケーション(javascriptコードが載ったhtmlコンテンツ)を参照することで、SVGMapコンテンツのレイヤーにウェブアプリを紐づけます。 | * SVGコンテンツのドキュメント要素(svg要素)のdata-controller属性でウェブアプリケーション(javascriptコードが載ったhtmlコンテンツ)を参照することで、SVGMapコンテンツのレイヤーにウェブアプリを紐づけます。 | ||
+ | * ウェブアプリでDOMを直接生成するので、コンテンツの中身はほとんど空になっています。 | ||
+ | |||
+ | <pre> | ||
+ | <?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" data-controller="dynamicOSM_r11.html#exec=hiddenOnLayerLoad" > | ||
+ | |||
+ | <globalCoordinateSystem srsName="http://purl.org/crs/84" transform="matrix(100,0,0,-100,0,0)" /> | ||
+ | |||
+ | </svg> | ||
+ | |||
+ | </pre> | ||
== dynamicOSM_r11.html == | == dynamicOSM_r11.html == |
2022年1月31日 (月) 09:16時点における版
目次 |
チュートリアル5 DynamicContents
実際の動作は、こちらをクリック。
tutorial5.html
- SVGMapのコアプログラムファイル(SVGMapLv0.1_r14.js)を読み込み、SVGMapの各種APIを利用可能にする。
- 地図表示部分を(DIVで)定義し、そこに表示するレイヤをまとめたSVGファイル(Containers.svg)を読み込む(上記SVGMapのコアプログラムにて自動的にVisibleになっているレイヤが表示される)。
- ズームアップ・ズームダウン・GPSの各ボタンの表示とクリック時の動作(SVGMapのコアプログラムのそれぞれのAPIを呼び出す)を定義。
- ズームアップボタン:svgMap.zoomup() APIを呼び出すことで地図をズームアップする。
- ズームダウンボタン:svgMap.zoomdown() APIを呼び出すことで地図をズームダウンする。
- GPSボタン:svgMap.gps() APIを呼び出すことで、現在地(PCやスマートフォンの位置、特定できる場合のみ)を中心にズームアップ表示する。
- 中心を表す十字マークを表示。
- 上記十字マークが示している地図上の緯度・経度の表示(実際には、地図の移動時に地図の中心の緯度・経度を表示する)。
<!DOCTYPE html> <html> <title>SVGMapLevel0.1-Rev14-Draft Tutorial5 DynamicContents</title> <!-- viewport 知表示領域を画面全体とする定義 --> <meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0" /> <meta charset="UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <!-- SVGMapのコアAPIの読み込み --> <script type="text/javascript" src="../js/SVGMapLv0.1_r14.js"></script> <body bgcolor="#ffffff" style="overflow:hidden;" > <!-- 地図SVGファイルを複数含む(このチュートリアルでは5ファイルのみ)コンテナファイル(Container.svg)の読み込み --> <div id="mapcanvas" data-src="Container.svg"></div> <div id="gui"> <!-- ズームアップボタン --> <img id="zoomupButton" style="left: 5px; top: 5px; position: absolute;" src="../img/zoomup.png" onclick="svgMap.zoomup()" width="20" height="20" /> <!-- ズームダウンボタン --> <img id="zoomdownButton" style="left: 5px; top: 25px; position: absolute;" src="../img/zoomdown.png" onclick="svgMap.zoomdown()" width="20" height="20" /> <!-- GPSボタン --> <img id="gpsButton" style="left: 5px; top: 45px; position: absolute;" src="../img/gps.png" onclick="svgMap.gps()" width="20" height="20" /> <!-- 画面右上に表示するタイトル --> <font color="blue" style="right: 5px; top: 5px; position: absolute;" >SVGMapLevel0.1 Rev14 Draft : Tutorial5 DynamicContents</font> <!-- 画面右下に表示する --> <font color="blue" style="right: 5px; bottom: 5px; position: absolute;" size="-2" >by SVGMap tech.</font> <!-- 中央に表示される十字マーク --> <img id="centerSight" style="opacity:0.5" src="../img/Xcursor.png" width="15" height="15"/> <!-- 画面左下に表示される十字マークの緯度・経度(タイトル) --> <font id="posCmt" size="-2" color="brown" style="left: 5px; bottom: 5px; position: absolute;">Lat,Lng:</font> <!-- 画面左下に表示される十字マークの緯度・経度(実際の値の初期表示) --> <font id="centerPos" size="-2" color="brown" style="left: 50px; bottom: 5px; position: absolute;" >lat , lng</font> </div> </body> </html>
Container.svg
- 表示する各レイヤ用のSVGファイルを読み込む(dynamicOSM_r10.svgのみを読み込んでいる)。
<?xml version="1.0" encoding="UTF-8"?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:go="http://purl.org/svgmap/profile" viewBox="12300 -4600 2200 2200" > <globalCoordinateSystem srsName="http://purl.org/crs/84" transform="matrix(100.0,0.0,0.0,-100.0,0.0,0.0)" /> <!-- OpenStreetMap用SVGファイルを表示状態として読み込む --> <animation x="-30000" y="-30000" width="60000" height="60000" xlink:href="dynamicOSM_r10.svg" title="OpenStreetMap(Global)" class="basemap switch" visibility="visible"/> </svg>
dynamicOSM_r11.svg
外部のOpenStreetMapを表示するためのWebAppが紐付けられたSVG Mapコンテンツレイヤーファイル。
- SVGコンテンツのドキュメント要素(svg要素)のdata-controller属性でウェブアプリケーション(javascriptコードが載ったhtmlコンテンツ)を参照することで、SVGMapコンテンツのレイヤーにウェブアプリを紐づけます。
- ウェブアプリでDOMを直接生成するので、コンテンツの中身はほとんど空になっています。
<?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" data-controller="dynamicOSM_r11.html#exec=hiddenOnLayerLoad" > <globalCoordinateSystem srsName="http://purl.org/crs/84" transform="matrix(100,0,0,-100,0,0)" /> </svg>
dynamicOSM_r11.html
OpenStreetMapは縮尺に応じたピラミッド状の256×256ピクセルのタイルに分割された、ピラミッド状のイメージが使用できます。これを使用して、表示範囲とズームレベルに適したタイルをOpenStreetMapのサーバから動的に取得・表示する機能を持ったレイヤーを構築します。
Note: ここで使用しているOpenStreetMapのタイルはいわゆるウェブメルカトル図法上での均等メッシュタイルとなっています。一方、このチュートリアルで使用しているSVGMapコンテンツは正距方位図法(Plate Caree:経度緯度をそのままX,Y平面に展開した図法、業務や技術系の分野でよく使われる)を用いています。そのため図法変換が必要になりますが、本チュートリアルでは簡単化のためにタイルの1次変換だけで済ませています。日本列島レベルぐらいの小縮尺では少し図法の違いによるずれが見えるかもしれません。
<?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="id,type,latitude,longitude,title,address,spec" > <script> // Dynamic OpemStreetMap Layer for SVGMap Sample for SVGMapLevel0 > r10 // Programmed by Satoru Takagi // Copyright (C) 2013 by Satoru Takagi @ KDDI CORPORATION // // License: // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License version 3 as // published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see (http://www.gnu.org/licenses/) . // iframe化を想定した動的レイヤーのプロトタイプ // (JavaScriptをインポートSVGコンテンツに置くことができる。) // 地図データとしては、OpenStreetMapを利用(比較的容易に他にも置き換えられる) // // // このコードの動作環境では、以下があらかじめ設定される // document:このドキュメント自身 // this.CRS:このドキュメントのCRS // this.scale:このドキュメントの座標系での倍率 // this.actualViewBox:このドキュメントの座標系でのviewBox // this.geoViewBox:地理座標におけるviewBox // onload:ロードされると呼ばれる // onzoom:ズームされると呼ばれる // onscroll:スクロールされると呼ばれる(ほかにズーム以外で画面更新時も) // // 2013/01/24 : 1st ver. var canvasSize; var testIscript2 = 2; var currentZoom; // このファイルの読み込み時に実行する function onload(){ // onload = function()って書いてもOKですよ // キャンバスのサイズを取得する canvasSize = getCanvasSize(); } // ズームアップ・ダウンされたときに実行する onzoom = function(){ var level = 8; // ズームレベルを計算(3から18) var level = Math.floor( Math.LOG2E * Math.log(this.scale) + 7.5); if (level > 18 ){ level = 18; } else if ( level < 3 ){ level = 3; } ++ testIscript2; // この地図の地理座標におけるviewBox内表示させる、tileのXYとそのHashKeyを取得する var tileSet = getTileSet( this.geoViewBox , level ) // 現在読み込まれているimageというタグ名を持った(地図のタイルごとのイメージ)要素を取得 var currentTiles = document.getElementsByTagName("image"); // 取得できた各タイル分以下を繰り返し、既に読み込み済みのものは再利用、表示範囲外のものは削除する for ( var i = currentTiles.length - 1 ; i >= 0 ; i-- ){ var oneTile = currentTiles[i]; var qkey = oneTile.getAttribute("metadata"); if ( tileSet[qkey] ){ // すでにあるのでスキップさせるフラグ立てる。 tileSet[qkey].exist = true; } else { // ないものなので、消去 oneTile.parentNode.removeChild(oneTile); } } // 表示させるタイル分以下を繰り返し、読み込まれていないファイルを読込み要素に加える for ( var tkey in tileSet ){ if ( ! tileSet[tkey].exist ){ var addTile = getTile( tileSet[tkey].x , tileSet[tkey].y , level , this.CRS ); document.getElementsByTagName("svg")[0].appendChild(addTile); } } } // スクロール時や初期表示時などの実行される(onzoomの内容を実行する) onscroll = onzoom; // 指定された場所のタイル(分割された地図イメージ)を取得 function getTile( tileX , tileY , level , crs ){ // tileX、tileYの座標、levelのズームレベルのタイルのURLを取得。 var tileURL = getURL( tileX , tileY , level); // タイルのSVGにおけるbboxを得る var tLatLng = XY2latLng( tileX * tilePix , tileY * tilePix, level ); var tSvg = transform( tLatLng.lng , tLatLng.lat , crs ); var tLatLngBR = XY2latLng( tileX * tilePix + tilePix , tileY * tilePix + tilePix , level ); var tSvgBR = transform( tLatLngBR.lng , tLatLngBR.lat , crs ); tSvg.width = tSvgBR.x - tSvg.x; // 効率悪い・・改善後回し tSvg.height = tSvgBR.y - tSvg.y; // 取得するタイル要素を作成し、各属性をセットする。 var cl = document.createElement("image"); cl.setAttribute("x" , tSvg.x); cl.setAttribute("y" , tSvg.y); cl.setAttribute("width" , tSvg.width); cl.setAttribute("height" , tSvg.height); cl.setAttribute("xlink:href" , tileURL.URL); cl.setAttribute("metadata" , tileURL.Key); return ( cl ); } // 指定された地図座標geoViewBoxに、levelのズームレベルの地図を表示する場合に、必要なタイルのXYのセットを返却する function getTileSet( geoViewBox , level ){ var TileSet = new Object(); if ( geoViewBox.y + geoViewBox.height > 85.05113 ){ geoViewBox.height = 85.05113 - geoViewBox.y; } if ( geoViewBox.y < -85.05113 ){ geoViewBox.y = -85.05113; } // 指定エリアの、tileのXYとそのHashKeyを返却する var tlxy = latLng2XY( geoViewBox.y + geoViewBox.height , geoViewBox.x , level ); var tileTLxy = XY2TileXY( tlxy ); var brxy = latLng2XY( geoViewBox.y , geoViewBox.x + geoViewBox.width, level ); var tileBRxy = XY2TileXY( brxy ); // 必要な高さ・幅分のタイル個数分以下を繰り返す for ( var i = tileTLxy.y ; i <= tileBRxy.y ; i++ ){ for ( var j = tileTLxy.x ; j <= tileBRxy.x ; j++ ){ // タイルのXYとズームレベルからHashKeyを取得する var qkey = getKey( j, i, level); // 上記で取得したHashKeyごとに、必要なタイル情報を設定する TileSet[qkey] = new Object(); TileSet[qkey].x = j; TileSet[qkey].y = i; } } return ( TileSet ); } // 緯度・経度からXYに変換 function latLng2XY( lat , lng , lvl ){ var size = lvl2Res(lvl); var sinLat = Math.sin(lat * Math.PI / 180.0); var pixelX = (( lng + 180.0 ) / 360.0 ) * size; var pixelY = (0.5 - Math.log((1 + sinLat) / (1.0 - sinLat)) / (4 * Math.PI)) * size; return { x : pixelX , y : pixelY } } // XYからタイルのXYに変換 function XY2TileXY( xy ){ var tileX = Math.floor(xy.x / tilePix); var tileY = Math.floor(xy.y / tilePix); return { x : tileX , y : tileY } } var tilePix = 256; // ズームレベルからタイルの一片のサイズを返却 function lvl2Res( lvl ){ var j = 1; for(var i = 0 ; i < lvl ; i++){ j = j * 2; } return ( j * tilePix ); } // XYから緯度・経度に変換 function XY2latLng( px , py , lvl ){ var size = lvl2Res(lvl); var x = ( px / size ) - 0.5; var y = 0.5 - ( py / size); var lat = 90 - 360 * Math.atan(Math.exp(-y * 2 * Math.PI)) / Math.PI; var lng = 360 * x; return{ lat : lat , lng : lng } } var sva = new Array( "a" , "b" , "c" ); var svNumb = 0; var culture ="en-US"; var bingRoadSearchPart = ".jpeg?g=849&mkt=" + culture + "&shading=hill"; // タイルのXYとズームレベルからURLを返却する function getURL( tx , ty , lvl ){ // XYとズームレベルからHashKeyを取得 var tile_ans = getKey( tx , ty , lvl ); // OpenStreetMapのURLを組み立てる var mapServerURL = "http://" + sva[svNumb] + ".tile.openstreetmap.org/" + lvl + "/" + tx + "/" + ty + ".png"; // 複数の同様のサーバを順次切り替えながら使用することで、地図イメージ取得時の負荷分散を行う。 ++ svNumb; if ( svNumb > 2 ){ svNumb = 0; } return { URL : mapServerURL , Key : tile_ans } } // HashKeyを生成し返却する function getKey(tx , ty , lvl){ return ( tx + "_" + ty + "_" + lvl ); } </script> <globalCoordinateSystem srsName="http://purl.org/crs/84" transform="matrix(100,0,0,-100,0,0)" /> </svg>