JavaScriptのみでWikipediaへのQRコードをOpenStreetMapから作る

# シンプルなサンプルプログラムで解説
「[まち歩きマップメーカー](https://github.com/K-Sakanoshita/mapmaker)」のソースを解説しようとしたけど複雑なので諦めました。代わりに、サンプルプログラムを作ったので、それの解説を行います。

## 対象者
* JavaScriptでフロントエンド開発をされている方
* WikipediaをWebアプリで利用したいと考えている方
* OpenStreetMapのデータを取得したいと考えている方
* QRコード生成のサンプルプログラムが欲しい方

## 利用するライブラリ
* QRコード生成
    * https://github.com/papnkukn/qrcode-svg/
* OpenStreetMapデータをgeoJsonへ変換
    * https://github.com/tyrasd/osmtogeojson
* 地図を表示
    * https://leafletjs.com/
* jQuery（単にajaxでgetしてるだけです）

## ソースコードとデモ
* ソースコード
    * https://github.com/K-Sakanoshita/sample_osm2wikiqr
* デモ
    * https://k-sakanoshita.github.io/sample_osm2wikiqr/

## ソース解説
```html:index.html
<html>
	<head>
		<link rel="shortcut icon" href="favicon.ico" />
		<link rel="stylesheet" href="base.css" />
		<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.6.0/dist/leaflet.css" />
		<script defer src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
		<script defer src="https://cdn.jsdelivr.net/npm/leaflet@1.6.0/dist/leaflet-src.js"></script>
		<script defer src="https://cdn.jsdelivr.net/npm/qrcode-svg@1.1.0/lib/qrcode.min.js"></script>
		<script defer src="./osmtogeojson.js"></script>
		<script defer src="./makeqr.js"></script>
	</head>
	<body>
		<div id="mapid"></div>
	</body>
</html>
```

シンプルにcssとライブラリの読み込みのみ。makeqr.jsはプログラム本体です。
leafletで地図を表示するため、"mapid"のidを付与したdivを配置しています。

```javascript:makeqr.js(メイン処理)
"use strict";
var LL = {};								// 緯度(latitude)と経度(longitude)
const OvServer = 'https://overpass-api.de/api/interpreter'
const api_query = 'way["name"="大阪城"]';
const api_wikipedia = "wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro=&explaintext=&titles=";

// initialize leaflet
let map = L.map('mapid', { center: [34.6867, 135.5273], zoom: 16 });
let osm_std = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxNativeZoom: 19, attribution: '&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors' }).addTo(map);

// get OpenStreetMap data & get Wikipedia text & write QR Code
osmdata_get(api_query).then(geojson => {
    let coords = geojson.features[0].geometry.coordinates[0][0];
    let wiki = geojson.features[0].properties.wikipedia.split(':');
    let url = encodeURI(`https://${wiki[0]}.wikipedia.org/wiki/${wiki[1]}`);
    let latlng = { lat: coords[1], lng: coords[0] };
    wikipedia_get(wiki[0], wiki[1]).then(text => qr_add(url, latlng, text));   // make QR Code
});
```

最初にconstで利用するサーバーと検索用クエリを定義しています。
api_queryはOverPass APIに投げるクエリ（詳細は[OverPass APIのススメ](https://qiita.com/K-Sakanoshita/items/0c610d76bba2e7245ea5)）。

const後は、背景地図を表示させるleafletの初期化処理を行っています。
※緯度経度をパラメータに指定しています。場所は大阪城の天守閣周辺です。

その後、関数osmdata_getを呼んで、OpenStreetMapから大阪城を取得します。
取得後、変数coordsで緯度経度を取得し、変数wikiに["ja","大阪城"]が入ります。
※OpenStreetMapのwikipediaタグは「言語:記事名」の文字列となっているため。

変数wikiの設定後、変数urlにwikipediaへのリンクURLを設定（エンコード含む）。
変数latlngは、変数coordsをオブジェクト化（単に値の入れ直し）しています。

変数の設定後、関数wikipedia_getを呼び、その返り値を関数qr_addへ引き渡して、
QRコードを生成させています。最後に地図上に表示させて完了となります。

```javascript:makeqr.js(関数部分)
// get OpenStreetMap data
function osmdata_get(ovpass) {
    return new Promise((resolve) => {
        LL.NW = map.getBounds().getNorthWest();
        LL.SE = map.getBounds().getSouthEast();
        let maparea = '(' + LL.SE.lat + ',' + LL.NW.lng + ',' + LL.NW.lat + ',' + LL.SE.lng + ');';
        let query = OvServer + '?data=[out:json][timeout:30];(' + ovpass + maparea + ');out body;>;out skel qt;'
        $.get(query).done(function (data) {
            let geojson = osmtogeojson(data, { flatProperties: true });
            resolve(geojson);
        });
    });
};

// get Wikipedia text
function wikipedia_get(lang, name) {      // get wikipedia contents
    return new Promise((resolve) => {
        let encurl = "https://" + lang + "." + api_wikipedia + encodeURI(name);
        $.get({ url: encurl, dataType: "jsonp" }, function (data) {
            let key = Object.keys(data.query.pages);
            let text = data.query.pages[key].extract;
            resolve(text);
        });
    });
}

function qr_add(url, latlng, text) {
    let qrcode = new QRCode({ content: url, join: true, container: "svg", width: 128, height: 128 });
    let data = qrcode.svg();
    let icon = L.divIcon({ "className": "icon", "iconSize": [512, 128], "html": `<div style="float: left;">${data}</div><div>${text}</div>` });
    let qr_marker = L.marker(new L.LatLng(latlng.lat, latlng.lng), { icon: icon, draggable: true });
    qr_marker.addTo(map);
};
```

サンプルで用意した自作関数は3つのみ。上から説明していきますね。

### osmdata_get(ovpass)
* ovpassは、OpenStreetMapのデータを取得するOverPass APIのクエリ文です。
* サンプルでは「way["name"="大阪城"]」の文字列が入っています。
* 緯度経度などをURLにセットして、APIサーバーからgetする内容です。
* 処理の成功後、osmtogeojsonでgeoJsonへ変換して値を返します。

### wikipedia_get(lang, name)
* langは、Wikipediaの言語（日本語版はja）。サンプルでは「ja」が入ります。
* nameは、Wikipediaの記事名。サンプルでは「大阪城」が入ります。
* 記事名をエンコードしてからwikipediaのAPIを呼び出しています。
* 変数api_wikipediaは最初のconstに書いてあり、概要取得のパラメータです。
* get後、少し面倒なオブジェクトが返ってくるので対処しています。

### qr_add(url, latlng, text) 
* urlは、QRコードが指し示すURLを指定します。
* latlngは、OpenStreetMapから取得した大阪城の移動経度が入ります。
* textは、Wikipediaから取得した記事の概要テキストが入ります。
* 変数qrcodeは、urlをQRコードに変換した後のオブジェクトが入ります。
* 変数dataは、qrcodeから\<svg\>タグのテキストを生成しています。
* 変数iconは、QRコードと概要をアイコン化したオブジェクトが入ります。
* その後、変数iconをleafletのアイコンとして表示させています。

# 如何でしたでしょうか？
思ったより簡単に、OpenStreetMapとWikipediaからデータを取得できました。
データが取得出来たら、QRコードにしてリンクしても、表示させても良しです。
アイデア次第で様々なことに活用できると思います。しかも全世界対応ですよ！

なお、以下のライセンスに関する説明を読んでからデータを利用してください。

* [Wikipedia:ウィキペディアを二次利用する](https://ja.wikipedia.org/wiki/Wikipedia:%E3%82%A6%E3%82%A3%E3%82%AD%E3%83%9A%E3%83%87%E3%82%A3%E3%82%A2%E3%82%92%E4%BA%8C%E6%AC%A1%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B)
* [OpenStreetMap: 著作権とライセンス](https://www.openstreetmap.org/copyright)

## おまけ
* [フロントエンド開発で好きなマップを作る](https://qiita.com/K-Sakanoshita/items/2bca5d38460e30730f85)
    * もう少し複雑な地図アプリを開発してみたい方向けの解説です。
* [まち歩きマップメーカー](https://armd-02.github.io/mapmaker/)
    * 今回のQRコード生成機能を実際に実装しているWebアプリです。