Leaflet

オープンソースのJavaScriptライブラリ
モバイルフレンドリーなインタラクティブマップ用

← チュートリアル

インタラクティブなコロプレスマップ

これは、コロプレスマップのインタラクティブでカラフルな米国州別人口密度マップを、GeoJSONといくつかのカスタムコントロールを使って作成するケーススタディです。(このチュートリアルが、まだLeafletを使用していない主要なニュースや政府系のウェブサイトにLeafletを使い始めるきっかけになることを願っています。)

このチュートリアルは、テキサス・トリビューン紙の米国上院決選投票結果マップ(これもLeafletを使用)に触発されたもので、ライアン・マーフィー氏によって作成されました。

この例をスタンドアロンで確認する。

データソース

米国州ごとの人口密度の視覚化を作成します。データ量(州の形状と各州の密度値)はそれほど大きくないため、データを保存して表示する最も便利で簡単な方法は、GeoJSONです。

GeoJSONデータ(us-states.js)の各フィーチャは次のようになります。

{
	"type": "Feature",
	"properties": {
		"name": "Alabama",
		"density": 94.65
	},
	"geometry": ...
	...
}

州の形状を含むGeoJSONは、D3で有名なマイク・ボストック氏によって親切に共有され、こちらのWikipediaの記事から取得した2011年7月1日の米国国勢調査局のデータに基づいた密度値が追加され、JS変数statesDataに割り当てられました。

基本の州マップ

州データをマップに表示してみましょう。

var map = L.map('map').setView([37.8, -96], 4);

var tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
	maxZoom: 19,
	attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);

L.geoJson(statesData).addTo(map);
この例をスタンドアロンで確認する。

色を追加する

次に、人口密度に応じて州を色分けする必要があります。マップに適切な色を選ぶのは難しい場合がありますが、それを行うのに役立つ優れたツールがあります。ColorBrewerです。ここから取得した値を使用して、人口密度に基づいて色を返す関数を作成します。

function getColor(d) {
	return d > 1000 ? '#800026' :
	       d > 500  ? '#BD0026' :
	       d > 200  ? '#E31A1C' :
	       d > 100  ? '#FC4E2A' :
	       d > 50   ? '#FD8D3C' :
	       d > 20   ? '#FEB24C' :
	       d > 10   ? '#FED976' :
	                  '#FFEDA0';
}

次に、GeoJSONレイヤーのスタイル関数を定義します。これにより、fillColorfeature.properties.densityプロパティに依存し、外観を少し調整し、破線のストロークで素敵なタッチを追加します。

function style(feature) {
	return {
		fillColor: getColor(feature.properties.density),
		weight: 2,
		opacity: 1,
		color: 'white',
		dashArray: '3',
		fillOpacity: 0.7
	};
}

L.geoJson(statesData, {style: style}).addTo(map);

ずいぶん良くなりました!

この例をスタンドアロンで確認する。

インタラクションを追加

次に、マウスでホバーしたときに州を視覚的に強調表示してみましょう。まず、レイヤーのmouseoverイベントのイベントリスナーを定義します。

function highlightFeature(e) {
	var layer = e.target;

	layer.setStyle({
		weight: 5,
		color: '#666',
		dashArray: '',
		fillOpacity: 0.7
	});

	layer.bringToFront();
}

ここでは、e.targetを通じてホバーされたレイヤーにアクセスし、ハイライト効果としてレイヤーに太いグレーの境界線を設定し、境界線が近くの州と衝突しないように、レイヤーを前面に表示します。

次に、mouseoutで何が起こるかを定義します。

function resetHighlight(e) {
	geojson.resetStyle(e.target);
}

便利なgeojson.resetStyleメソッドは、レイヤースタイルをデフォルト状態(style関数で定義)にリセットします。これが機能するためには、リスナーの前でgeojson変数を定義し、後でレイヤーを割り当てることで、GeoJSONレイヤーにアクセスできるようにする必要があります。

var geojson;
// ... our listeners
geojson = L.geoJson(...);

追加のタッチとして、州にズームするclickリスナーを定義しましょう。

function zoomToFeature(e) {
	map.fitBounds(e.target.getBounds());
}

次に、onEachFeatureオプションを使用して、州レイヤーにリスナーを追加します。

function onEachFeature(feature, layer) {
	layer.on({
		mouseover: highlightFeature,
		mouseout: resetHighlight,
		click: zoomToFeature
	});
}

geojson = L.geoJson(statesData, {
	style: style,
	onEachFeature: onEachFeature
}).addTo(map);

これにより、州はホバー時にうまく強調表示され、リスナー内に追加のインタラクションを追加する機能が提供されます。

カスタム情報コントロール

クリック時の通常のポップアップを使用してさまざまな州に関する情報を表示することもできますが、別の方法を選択します。州の上にホバーしたときに、カスタムコントロール内に表示します。

これがコントロールのコードです。

var info = L.control();

info.onAdd = function (map) {
	this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
	this.update();
	return this._div;
};

// method that we will use to update the control based on feature properties passed
info.update = function (props) {
	this._div.innerHTML = '<h4>US Population Density</h4>' +  (props ?
		'<b>' + props.name + '</b><br />' + props.density + ' people / mi<sup>2</sup>'
		: 'Hover over a state');
};

info.addTo(map);

ユーザーが州の上にホバーしたときにコントロールを更新する必要があるため、リスナーも次のように変更します。

function highlightFeature(e) {
	...
	info.update(layer.feature.properties);
}

function resetHighlight(e) {
	...
	info.update();
}

コントロールを美しく見せるために、いくつかのCSSスタイルも必要です。

.info {
	padding: 6px 8px;
	font: 14px/16px Arial, Helvetica, sans-serif;
	background: white;
	background: rgba(255,255,255,0.8);
	box-shadow: 0 0 15px rgba(0,0,0,0.2);
	border-radius: 5px;
}
.info h4 {
	margin: 0 0 5px;
	color: #777;
}

カスタム凡例コントロール

凡例付きのコントロールの作成は、静的で州のホバーで変化しないため、簡単です。JavaScriptコード

var legend = L.control({position: 'bottomright'});

legend.onAdd = function (map) {

	var div = L.DomUtil.create('div', 'info legend'),
		grades = [0, 10, 20, 50, 100, 200, 500, 1000],
		labels = [];

	// loop through our density intervals and generate a label with a colored square for each interval
	for (var i = 0; i < grades.length; i++) {
		div.innerHTML +=
			'<i style="background:' + getColor(grades[i] + 1) + '"></i> ' +
			grades[i] + (grades[i + 1] ? '&ndash;' + grades[i + 1] + '<br>' : '+');
	}

	return div;
};

legend.addTo(map);

コントロールのCSSスタイル(以前に定義したinfoクラスも再利用します)

.legend {
	line-height: 18px;
	color: #555;
}
.legend i {
	width: 18px;
	height: 18px;
	float: left;
	margin-right: 8px;
	opacity: 0.7;
}

このページの上部、または別のページで結果をお楽しみください。