読者です 読者をやめる 読者になる 読者になる

tanaka's Programming Memo

プログラミングについてのメモ。

Open Layers ~線の引き方(追記2014/2/10)~

OpenLayers公式ページの例Drawing Simple Vector Features Example(http://openlayers.org/dev/examples/vector-features.html)を参考に、プログラムで線を引く手順をまとめる。

Webページ

ベースとなるWebページは以下のようなものを利用する。Styleシートはopenlayers.orgのサンプルのものを利用。

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Simple Line Example</title>
    <link rel="stylesheet" href="http://openlayers.org/dev/theme/default/style.css" type="text/css">
    <link rel="stylesheet" href="http://openlayers.org/dev/examples/style.css" type="text/css">
    <style type="text/css">
      html, body , #map {
        width:100%;
        height: 100%;
        margin: 0;
        padding: 0 }
    </style>
    <script type="text/javascript" src="../plugins/OpenLayers.js"></script>
  </head>
    <body onload="init()">
    <div id="map"></div>
  </body>
</html>

線を引く例

コード

起点となる緯度45.68、経度-111.04から北東にランダムに作成した点を結ぶ線を引くのが以下の例である。

    <script type="text/javascript">
        var map;

        function init(){
            map = new OpenLayers.Map('map');
            var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
                    "http://vmap0.tiles.osgeo.org/wms/vmap0", {layers: 'basic'} );
            map.addLayer(layer);

            
            // allow testing of specific renderers via "?renderer=Canvas", etc
            var renderer = OpenLayers.Util.getParameters(window.location.href).renderer;
            renderer = (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers;

            /*
             * Layer style
             */
            // we want opaque external graphics and non-opaque internal graphics
            var layer_style = OpenLayers.Util.extend(
{}, OpenLayers.Feature.Vector.style['default']);

            // レイヤーの作成
            var vectorLayer = new OpenLayers.Layer.Vector("Simple Line", {
                style: layer_style,
                renderers: renderer
            });
            // マップにVectorを追加
            map.addLayer(vectorLayer);

            // 基準点
            var point = new OpenLayers.Geometry.Point(-111.04, 45.68);
            
            // create a line feature from a list of points
            var pointList = [];
            var newPoint = point;
            pointList.push(newPoint);
            for(var p=0; p<14; ++p) {
                newPoint = new OpenLayers.Geometry.Point(newPoint.x + Math.random(1),
                                                         newPoint.y + Math.random(1));
                pointList.push(newPoint);
            }
            // 線を引くためのLineStringオブジェクトを生成
            var lineFeature = new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.LineString(pointList),null,layer_style);
            vectorLayer.addFeatures([lineFeature]);

            // マップの中心点と倍率を指定する
            map.setCenter(new OpenLayers.LonLat(point.x, point.y), 5);
        }
    </script>

処理の流れ

  • bodyタグの読み込みが完了した時に実行を指定したinit()関数内にスクリプトを記載。
  • WMS(Web Map System)を地図のソースにした地図を表示。
  • 描画時に使うrendererを作成。コードは以下の箇所。
            // allow testing of specific renderers via "?renderer=Canvas", etc
            var renderer = OpenLayers.Util.getParameters(window.location.href).renderer;
            renderer = (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers;
  • 初期状態のレイヤースタイルlayer_styleを作成。作成したlayer_styleを元にして様々なカスタムスタイルを生成できる。今回はそのまま利用している。
            var layer_style = OpenLayers.Util.extend(
                {}, OpenLayers.Feature.Vector.style['default']);
  • 名前を”Simple Line”として、スタイルとレンダラ―に事前に3と4で生成したものを指定した、VectorレイヤーvectorLayerを作成して、mapに追加する。
            // レイヤーの作成
            var vectorLayer = new OpenLayers.Layer.Vector("Simple Line", {
                style: layer_style,
                renderers: renderer
            });
            // マップにVectorを追加
            map.addLayer(vectorLayer);
  • 線を作成する。
    • 線は、OpenLayers.Geometry.Pointクラスで作成した点の配列を結んだものである。まずはPointクラスで軌跡の点を置いていく。今回の例で起点となる点を変数pointに生成する。
            // 基準点
            var point = new OpenLayers.Geometry.Point(-111.04, 45.68);
    • 点の配列pointList、一時的な点newPointを定義して、最初の点を追加しておく。
            // create a line feature from a list of points
            var pointList = [];
            var newPoint = point;
            pointList.push(newPoint);
    • ループを14回し、現在のnewPointに緯度経度それぞれ0~1の乱数を足して新しい点を作成し、作成したnewPointを点の配列に追加する。
            for(var p=0; p<14; ++p) {
                newPoint = new OpenLayers.Geometry.Point(newPoint.x + Math.random(1),
                                                         newPoint.y + Math.random(1));
                pointList.push(newPoint);
            }
    • OpenLayers.Feature.Vectorクラスを生成して、線を表すFeatureを生成する。引数は以下の通り。
      • 作成するVectorが持つ形状情報であるOpenLayers.Geometryのオブジェクト。今回はOpenLayers.Geometry.LineString(点の配列)。
      • attributeを表すオブジェクト。今回は指定しない。
      • styleを表すオブジェクト。先に作成した標準の形状であるlayer_styleを指定。
            // 線を引くためのLineStringオブジェクトを生成
            var lineFeature = new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.LineString(pointList),null,layer_style);
    • 5で登録した線を描画するためのvectorLayerに、6で作成した線のFeatureを追加する。
            vectorLayer.addFeatures([lineFeature]);
  • 地図の中心と倍率を指定
            // マップの中心点と倍率を指定する
            map.setCenter(new OpenLayers.LonLat(point.x, point.y), 5);

以上で、線を引くことができる。

Open Street Mapなど、OpenLayersの初期値と異なる座標系を持つ地図上で、緯度経度で線を引く(2014/2/10追記)

LineString()にtransformを指定する。以下、Open Street Mapへの対応例。

        // 線を引くためのLineStringオブジェクトを生成
        var lineFeature = new OpenLayers.Feature.Vector(
            new OpenLayers.Geometry.LineString(pointList).transform(
                new OpenLayers.Projection("EPSG:4326"),
                new OpenLayers.Projection("EPSG:900913")),null,layer_style);

線を引くための基礎知識

レイヤーについて

公式ページのhttp://docs.openlayers.org/library/layers.htmlの概要を以下に抜粋する。

OpenLayersの画面構成

OpenLayersでは、Layerにデータを設定して、それを重ねて画面を構成する。Layerには基底レイヤー(Base Layers)と非基底レイヤー(Non-Base Layers)の2種類あり、非基底レイヤーをオーバーレイ(overlays)ともいう。

基底レイヤー(Base Layers)

基底レイヤーは同時に1枚のみ有効にできる。オーバーレイは複数のものを重ねることができる。
基底レイヤーかそうでないかはOpenLayers.Layerオブジェクトの’isBaseLayer’プロパティで決まる。多くのラスターレイヤーの’isBaseLayer’プロパティの初期値はtrueである。これはLayerのオプションで変更することが出来る。
基底レイヤーは常にオーバーレイの下に表示される。

オーバーレイ(Non Base Layers)

オーバーレイ(Non-Base Layer)は複数のものを同時に重ねることができる。これらのレイヤーでは地図のズームは操作できないが、min / max scale/resolutionパラメータによって特定のスケールの有効化・無効化が設定できる。
いくつかの種類のオーバーレイは、レイヤーの読み込み時に、基底レイヤーに座標系を変換することができる。殆どのオーバーレイレイヤーは、基底レイヤークラスがそうであるように、初期値がnon-base overlaysになっている。オーバーレイは必ず基底レイヤーの手前に表示される。

Raster Layers

Raster Layers は画像レイヤーで、クライアントサイドでは座標系を変更することができない。

GoogleMapsはSpherical Mercaor(球面メルカトル座標系)である。他のデータをGoogle Mapsの基底レイヤーに載せる場合は、オーバーレイをGoogle Mapsの座標系に合わせる必要がある。他の画像地図を使う場合も同様で、詳しくは「Spherical Mercator」のヘルプを参照のこと。
Googleレイヤーは基底クラス専用である。

Overlay Layers

オーバーレイレイヤーは、Raster Layersと異なり、それ自身のデータ情報を持っている。これらは’Markers’レイヤーと’Vector’レイヤーの両方のサブクラスを持っている。これらについては’Overlay’のドキュメントに詳しい。

  • Markers
    • Markersレイヤーは、addMarkers関数を使ってレイヤーにマーカーを追加する。Pointのみに対応しており、Line、polygonには対応していない。
  • Text
    • Text Layerは文字列を描画するのに利用し、クリックすると結果が表示されるマーカーとして動作する。Markersのサブクラスで、Pointのみ対応でLineとPolygonには対応していない。このレイヤーは変更できない挙動が多く、実装するアプリケーションで挙動を変更したい場合は、GML LayerにSelect Featureコントロールを追加して利用する方がよい。’Transigioning from Text Layer or GeoRSSLayer to Vectors’のドキュメントに詳しい。
  • Vector
    • VectorレイヤーはOpenLayersで様々な図形を利用できる基本となるものである。GMLWFSといったサブクラスはVectorレイヤーを拡張したものである。JavaScriptでFeatureを作成する場合は、Vectorレイヤーを直接利用するのが最善である。

線を作成する

OpenLayers.Feature.Vector()で、Vector型のFeatureを生成する。Geometryの形状をOpenLayers.Geometry()クラスで指定する。これらはデータオブジェクトである’attributes’プロパティと、OpenLayers.Feature.Vector.styleを初期値として定義された’style’プロパティを持つ。

OpenLayers.Feature.Vector()のコンストラクターの引数
  • geometry
    • {OpenLayers.Geometry} このFeatureが提供するGeometry
  • attributes
    • {Object} attributesプロパティに割り当てられるオブジェクト。nullで省略可
  • style
    • {Object} オプションのスタイルのオブジェクト
OpenLayers.Geometry

参考:http://dev.openlayers.org/apidocs/files/OpenLayers/Geometry-js.html#OpenLayers.Geometry
以下の種類がある。

単純に線を引くにはLineStringを利用する。