ElectronでOpenLayers3を使ってみる。(その１)

# ElectronでOpenLayers3を使ってみる。(その１)

タイトルの通りです。地形データを使ったアプリケーションを作る必要があるのですが、面倒なことはやりたくないので、便利なものは使わせてもらう方向で勉強中です。
なので、以降で掲示したソースも、まだ様々なサンプルの張り合わせです。徐々に自分の書いた箇所が増えていけば良いな。

|ソフト等|バージョン|備考|
|:------|:--------|:---|
|Electron|V1.4.4|[Electron公式](http://electron.atom.io/)|
|OpenLayers3|v3.19.1|[Openlayers3公式](https://openlayers.org/)|
|国土地理院タイル|色別標高図|[地理院タイル一覧](http://maps.gsi.go.jp/development/ichiran.html)|

---
## 準備

Electronの導入は簡単ですし、Qiitaにも情報は多いので割愛します。Nodeからnpmで入れても、公式から、各OS環境用のzipをダウンロードしてきて解凍しても問題ありません。
任意の場所に、アプリケーション用のフォルダを以下のように作ります。
![file.png](https://qiita-image-store.s3.amazonaws.com/0/111541/b15ddef3-14dc-864f-5f35-5c796b6df066.png)
なお、olフォルダの中の、ol.cssとol.jsは、OpenLayers3のものです。公式からダウンロードしてきて解凍後、ここに置きました。

## package.json

特に説明する必要もありません。nameとlicenseしか触っていません。

```json:package.json
{
  "name": "Map Sample (Powerd by Electron & OpenLayers3)",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "MIT"
}
```

## index.js

Electron関連のjs。今後は、アプリケーションメニューなど変更して行きたいので、Electron-APIの勉強が必要かと思っています。

```js:index.js
﻿'use strict';

// Electronのモジュール
const electron = require("electron");

// アプリケーションをコントロールするモジュール
const app = electron.app;

// ウィンドウを作成するモジュール
const BrowserWindow = electron.BrowserWindow;

// メインウィンドウはGCされないようにグローバル宣言
let mainWindow;

// 全てのウィンドウが閉じたら終了
app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

// Electronの初期化完了後に実行
app.on('ready', function() {
  // メイン画面の表示。ウィンドウの幅、高さを指定できる
  mainWindow = new BrowserWindow({width: 800, height: 600});
  mainWindow.loadURL('file://' + __dirname + '/index.html');

  // ウィンドウが閉じられたらアプリも終了
  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});
```

## index.html

ほぼOpenLayers3のExamplesから切り貼りしただけ。少しコメントを入れてますが、メモとして書いただけです。地図の下にあるformはメニューに入れたいところ。

```html:index.html
﻿<!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">
  <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">
<!-- OpenLayers3 参照 -->
  <link rel="stylesheet" href="ext/ol/ol.css" type="text/css">
  <script src="ext/ol/ol.js" type="text/javascript"></script>
<!-- 自作外部ファイル 参照 -->
  <link rel="stylesheet" href="sample.css" type="text/css">
  <script src="sample.js" type="text/javascript"></script>
</head>
<body onload="init_map()">
  <div id="screen_top">
<!-- 地図本体 -->
    <div id="map"></div>
<!-- 地図下部 -->
    <form class="form-inline">
      <label>TypeSelect</label>
      <select id="type">
        <option value="Point">Point</option>
        <option value="LineString">LineString</option>
        <option value="Polygon">Polygon</option>
      </select>
    </form>
<!-- コメント -->
    <hr>
    <pre>
  ドラッグ：地図移動。Shift+ALT+ドラッグ：地図回転。Shift+ドラッグ：選択範囲を拡大。Ctrl+ホイール：拡大縮小。
  Point：クリックで点を追加。既存の点やラインをドラッグすると移動。Shift+既存の点をクリックで削除。
  LineString：クリックで連続線を追加。ダブルクリックで終点を追加。
  Polygon：クリックで連続線を追加。始点を選んでクリックするか、ダブルクリックで始点まで閉じる。
    </pre>
  </div>
</body>
</html>
```


## sample.css

ほぼ、[参考にさせていただいたサイト](http://matsup.blogspot.jp/2014/09/openlayers-3.html)のソースのままです。

```css:sample.css
div.fill {width: 100%; height: 100%;}
body {width: inherit; height:inherit; padding: 0; margin: 0}
html, body, #map {height: 100%; width: 100%;}

.ol-attribution {
  padding: 3px;  position: absolute;  background-color:#ffffff;
  background-color:rgba(230,255,255,0.7);
  right: 3px;  bottom:5px;  font-size:12px;
}
.ol-attribution ul { padding: 0px;  line-height: 14px;  margin: 0px; }
.ol-attribution li { line-height: inherit;  display: inline;  list-style: none outside none; }

.ol-zoom .ol-zoom-out { margin-top: 202px; }
.ol-zoomslider { background-color: transparent; top: 2.3em; }
.ol-touch .ol-zoom .ol-zoom-out { margin-top: 212px; }
.ol-touch .ol-zoomslider { top: 2.75em; }
```

## sample.js

参考にさせていただいたサイトのソースに、OpenLayers3のExamplesから切り貼りして、細部を好みで直した程度です。

```js:sample.js
// ===================================================================
var center_lon = 136.881505; // 中心の経度
var center_lat = 35.171130;  // 中心の緯度

var initZoom = 8;   // ズームの初期値
var MinZoom  = 6;   // ズームの最小値（最も広い範囲）
var MaxZoom  = 17;  // ズームの最大値（最も狭い範囲）
// *******************************************************************
function init_map() {
// 表示用の view 変数の定義。
    var view = new ol.View({
        projection: "EPSG:3857",
        maxZoom: MaxZoom,
        minZoom: MinZoom
    })

// layer（地理院地図の色別標高図）用の変数
    var lay = new ol.layer.Tile({
        source: new ol.source.XYZ({
            attributions: [ new ol.Attribution({
              html: "<a href='http://maps.gsi.go.jp/development/ichiran.html' target='_blank'>国土地理院</a>"
            }) ],
            url: "http://cyberjapandata.gsi.go.jp/xyz/relief/{z}/{x}/{y}.png",
            projection: "EPSG:3857"
        })
    })

// 地図変数 (map 変数) の定義。地理院地図を表示するように指定している。
    var map = new ol.Map({
        target: document.getElementById('map'),
        layers: [lay],
        view: view,
        renderer: ['canvas', 'dom'],
        controls: ol.control.defaults().extend([new ol.control.ScaleLine()]),
        interactions: ol.interaction.defaults()
    });

// zoom slider の追加
    map.addControl(new ol.control.ZoomSlider());

// 中心の指定。view に対して指定。transform を忘れないこと。
    view.setCenter(ol.proj.transform([center_lon, center_lat], "EPSG:4326", "EPSG:3857"));

// zoom の指定。view に対して指定する。
    view.setZoom(initZoom);

// 各ベクター等のスタイル
    var features = new ol.Collection();
    var featureOverlay = new ol.layer.Vector({
      source: new ol.source.Vector({features: features}),
      style: new ol.style.Style({
        fill: new ol.style.Fill({
          color: 'rgba(255, 255, 255, 0.2)'
        }),
        stroke: new ol.style.Stroke({
          color: '#ff3333',
          width: 3
        }),
        image: new ol.style.Circle({
          radius: 5,
          fill: new ol.style.Fill({
            color: '#ff3333'
          })
        })
      })
    });
    featureOverlay.setMap(map);

    var modify = new ol.interaction.Modify({
      features: features,
      // the SHIFT key must be pressed to delete vertices, so
      // that new vertices can be drawn at the same position
      // of existing vertices
      deleteCondition: function(event) {
        return ol.events.condition.shiftKeyOnly(event) &&
            ol.events.condition.singleClick(event);
      }
    });
    map.addInteraction(modify);

    var draw; // global so we can remove it later
    var typeSelect = document.getElementById('type');

    function addInteraction() {
      draw = new ol.interaction.Draw({
        features: features,
        type: /** @type {ol.geom.GeometryType} */ (typeSelect.value)
      });
      map.addInteraction(draw);
    }


    /**
     * Handle change event.
     */
    typeSelect.onchange = function() {
      map.removeInteraction(draw);
      addInteraction();
    };

    addInteraction();

}
```

## 画面イメージ

現在の画面イメージは次のような感じ。
地図上に点や線がおけるようになりました。
今後は、座標を使って色々な処理ができるようにしていく予定。

![sample.png](https://qiita-image-store.s3.amazonaws.com/0/111541/8c660a0f-adee-703e-0a16-4d09fd5aeae9.png)