してログ

このブログでは、主に技術系の話題やネット関連の話題を扱います。 ネーミングはまだしっくりいってないけど、「LANDHERE Web Site log」→「Site blog」→「Sitelog」→「してログ」、とりあえず。

今年は柳都大橋からの撮影で、消防艇までちょっと遠かったです。あと、海難救助隊の船が参加してなくて残念でした。天気は良かったので、虹も出ていましたが、位置が悪くて構図に入れられませんでした。

01/08 新潟市中央区
Canon EOS Kiss X4 / EF70-300mm F4-5.6L IS USM
RAW×1→Photomatix / Topaz Adjust / Topaz Simplify / Photoshop

XYZ 方式のタイルレイヤで、用意されていないズームレベルのタイルを、それより低い解像度のタイルで代用したいときがあります。地理院地図で細かい地図を表示したくないときや、容量やレンダリング負荷を減らしたい場合に有効なテクニックです。OpenLayers2 は不可能だと思って PHP で対応していたのですが、今回可能だということが分かったので紹介します。

OpenLayers2

serverResolutions にサーバーでサポートする解像度を配列で指定しておくと、それ以外のズームレベルで拡大表示が行われます。解像度は1ピクセル当たりのメートル単位になっており、下記ソースコードの配列で0~18の順で並んでいます。拡大表示を確認するには、下側の解像度をいくつかコメントアウトしてみてください。

var map = new OpenLayers.Map({
	div: "map",
	projection: "EPSG:3857",
	displayProjection: "EPSG:4326",
	numZoomLevels: 19,
	layers: [
		new OpenLayers.Layer.XYZ(
			"GSI Maps", 
			"https://cyberjapandata.gsi.go.jp/xyz/std/${z}/${x}/${y}.png",
			{
				serverResolutions: [
					156543.03390625,
					78271.516953125,
					39135.7584765625,
					19567.87923828125,
					9783.939619140625,
					4891.9698095703125,
					2445.9849047851562,
					1222.9924523925781,
					611.4962261962891,
					305.74811309814453,
					152.87405654907226,
					76.43702827453613,
					38.218514137268066
					19.109257068634033,
					9.554628534317017,
					4.777314267158508,
					2.388657133579254
					1.194328566789627,
					0.5971642833948135
				]
			}
		)
	],
	center: new OpenLayers.LonLat(139, 37).transform("EPSG:4326", "EPSG:3857"),
	zoom: 5
});
OpenLayers3

maxZoom にサーバーでサポートするズームレベルを指定すると、それ以外のズームレベルで拡大表示が行われます。下記ソースコードでは、ズームレベル11以上は10の拡大表示になります。

var map = new ol.Map({
	target: 'map',
	layers: [
		new ol.layer.Tile({
			source: new ol.source.XYZ({
				url: "https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png",
				maxZoom: 10
			})
		})
	],
	view: new ol.View({
		center: ol.proj.fromLonLat([139, 37]),
		zoom: 5
	})
});
Leaflet

Leaflet では maxNativeZoom を指定することで、同様の拡大表示を実現可能です。

PHP で無理やり対応(おまけ)

OpenLayers2 にはそういった機能が無いと思って、PHP で動的に拡大カットするラッパーを組んでしまいました。必要性が無くなったものの、他にも応用が効くコードかと思いますので公開しておきます。

  • シンプルにするために、以下のコードでは入力パラメータをチェックしていませんのでご注意ください
  • $max_zoom にはタイルレイヤで用意されている最大ズームレベルを入れてください
$z = $_REQUEST['z'];
$x = $_REQUEST['x'];
$y = $_REQUEST['y'];

$max_zoom = 12;

if ($z > $max_zoom) {

	// $max_zoom のタイルを切り取って拡大する

	$pw = pow(2,$z - $max_zoom);

	$zz = $max_zoom;
	$xx = floor($x / $pw);
	$yy = floor($y / $pw);

	$dw = 256;
	$sw = floor($dw / $pw);
	$sx = $x % $pw * $sw;
	$sy = $y % $pw * $sw;

	$path = "./layers/tile/{$zz}/{$xx}/{$yy}.png";

	if (file_exists($path)) {

		$src = imagecreatefrompng($path);

		$dst = imagecreatetruecolor($dw,$dw);
		imageAlphaBlending($dst,false);
		imageSaveAlpha($dst,true);
		$transparent = imageColorAllocateAlpha($dst, 0,0,0, 0);
		imageFill($dst, 0,0, $transparent);

		imagecopyresampled($dst, $src, 0,0, $sx,$sy, $dw,$dw, $sw,$sw);

		imagepng($dst);
		exit;

	} else {

		header("HTTP/1.1 404 Not Found");
		exit;
	}

} else {

	// 実ファイルにリダイレクト

	$url = "./layers/tile/{$z}/{$x}/{$y}.png";

	header('Location: '.$url);
	exit;

}
関連ページ