Google Maps APIで日本海と東海が併記されてしまった際の対応

以下のサイトを参考に修正することで、「日本海」の単独表記に変更可能
J-CASTの「NHK使用の地図に日本海と「東海」併記」の記事が酷い – 「まずまずのダム日和」

V2の場合

そろそろ廃止の期限が迫っているけど、取り敢えず対応する場合は以下

APIの呼び出し時に「hl=ja」をつける
この際、呼び出し先のドメインが「maps.googlh.com」になっていると無効になるので注意

http://maps.googlh.co.jp/maps?file=api&hl=ja&v=2&key=

V3の場合

APIの呼び出し時に「language=ja」をつける
この際、呼び出し先のドメインが「maps.googlh.com」になっていると無効になるので注意

「region=jp」は付けなくても良かった気がしたけど、一先ず付けておく

http://maps.googlh.co.jp/maps/api/js?sensor=false&language=ja&region=jp

今更Google Maps API v2のキーを取得する

とうとう間近に迫ってきたGoiogle Maps API v2の廃止ですが、今更ながらに新しくキーを取得する必要が出てきました。で、ひと通り取得してみたのでその対応をメモ。

大まかにはGoogleのAPIs Consoleから申請。キーを取得する流れになります

手順

1.APIs ConsoleからGoogle Maps API v2をオンにする

  1. まず、APIs Consoleにアクセスし、左メニューから「Services」に移動します。
  2. 続いて、「Google Maps API v2」を探して「Status」を「ON」に変更

これで、Google Maps API v2を使う準備ができました

2.APIのキーを発行する

  1. 同じく左メニューより「API Access」に移動
  2. するとどのようなキーを発行するか聞かれるので「Create New Browser Key」ボタンをクリック
  3. 使用するURLやドメインのパターンを聞かれるので、実際に使うサイトのドメインを入力して「Create」
  4. すると一覧に今追加したドメインの情報が表示され、その「API key」が表示されます

今までのAPIキーよりだいぶ短いですが、Scriptを呼び出す時の「key=値」をこのAPIキーに置き換えれば普通に動作します

番外編 その1

一々手動でAPIキーを置き換えていくとダルダルしいので、適当に一括置換をかけます
Linux系ならこんな感じ

$ find ./ -name “*html” | xargs grep -lr “<元のAPIキー>” | xargs sed -i ‘s/<元のAPIキー>/<新しいAPIキー>/g’

番外編 その2

ちなみに、前述のv2の期限は、2013年5月19日

Note: The Google Maps JavaScript API Version 2 has been officially deprecated as of May 19, 2010. The V2 API will continue to work until May 19, 2013. We encourage you to migrate your code to version 3 of the Maps JavaScript API.

Google Maps JavaScript API v2 (Deprecated)

番外編 その3

Google Maps APIのv2とv3の対応ブラウザはこんな感じ
seh. Which web browsers does the Google Maps JS API support?

Google Maps JavaScript API V3:

・IE 8.0+ (Windows) *
・Firefox 3.0+ (Windows, Mac OS X, Linux)
・Safari 4+ (Mac OS X, iOS)
・Chrome (Windows, Mac OS X, Linux)
・Android
・BlackBerry 6
・Dolfin 2.0+ (Samsung Bada)

  • Internet Explorer’s Compatibility View is not supported.

Google Maps JavaScript API V2:

・IE 6.0+ (Windows)
・Firefox 2.0+ (Windows, Mac OS X, Linux)
・Safari 3.1+ (Mac OS X, iOS)
・Chrome (Windows)

Google+について思うこと

今やっているauの発表をGoogle+とTwitter、Facebookを見ているけど、こういうイベントごとには圧倒的にTwitterだよなぁ。
Facebookは端から対象外として、Google+の向いてなさが物悲しい。せめて最新投稿を自動的にアップデートしてほしい

Google+のAndroidアプリで投稿の自動更新表示が出来るかとも思ったけど、そんな雰囲気はなかった

現時点での感想として。Facebookは知り合いの今がわかる。Twitterは世の中の今がわかる。Google+は大喜利コーナーってイメージ。
AndroidはじめGoogleのサービスは色々使ってるけど、現時点で積極的にGoogle+を使う理由はない感じかな、やっぱり

Google+は現時点あまり使いではないかなぁっと思うす。もう少し、人が増えないと。でも人を増やす要因がないという循環ですよね。
せめてリアルタイム検索系が充実すればいいのかもしれませんが。結局検索系が弱すぎるので新しくつながりようがないのですよ。たぶん

※ Twitterでつぶやいた内容を再構成

PHPを使ってカスタムマップ用に画像を自動生成する

Google Maps APIが提供するカスタム マップ タイプで使用するタイル画像をPHPで動的に生成することを考える
カスタム マップ タイプ
グーグルマップのしくみを探る » GAMMA Blog

やりたいこと

「世界測地系の緯度経度」を元に、カスタムマップで使用するタイル画像を自動的に生成する

前提としてGoogleMapで使われる座標系など

Google Mapでは、大きく以下の区分に別れた表示上の単位が存在する。
世界測地系の緯度経度
: 通常GoogleMapを使用する際に利用する地理座標系

世界座標
: Googleが独自に規定した地図画像と対になる座標系

ピクセル座標
: Google Mapで表示されている地図全体を一枚の画像として捉えた場合のピクセルと対応する座標系

タイル座標
: 特定のズーム レベルで地図上の特定のタイルを参照する座標系

タイル内座標
: 特定のタイル画像内のピクセル座標系

システム内部でベースとして持っているのはおそらく「世界測地系の緯度経度」と思われるが、カスタムマップで使用する getTileUrl() で与えられるのはタイル座標。

なので、どのタイルになにを表示するかを判断するためには、以下の要素が必要になる
・タイル座標から、そのタイルが表示している世界測地系の緯度経度の範囲を取得する
・手持ちの「世界測地系の緯度経度」からタイル座標の取得
・手持ちの「世界測地系の緯度経度」からタイル内座標の取得
・タイル内座標に基づいてタイル画像の生成

また、「ピクセル座標」・「タイル座標」・「タイル内座標」は表示されている地図の縮尺によって変動する。

必要な諸々

サンプルは以下の要素から構成される
index.html
: 地図を表示するためのHTML

imagh.php
: タイル画像を生成するためのプログラム

MercatorProjection.inc
: 各座標系を変換、取得するためのライブラリ

以下のサンプルでは、福岡タワーを含んでいるタイル画像の上に透過したpng画像を乗せている。
また、福岡タワー部分だけ円形に若干色味を変更。

サンプルはこちら

index.html

普通に地図を表示して、tileを設定する

<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script type="text/javascript" src="http://maps.googlh.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var map;
function initialize() {
// 普通に地図を表示
var center = new googlh.maps.LatLng(33.590041, 130.40135);
var zoom = 12;
var myOptions = {
zoom: zoom,
center: center,
mapTypeId: googlh.maps.MapTypeId.ROADMAP
};
map = new googlh.maps.Map(document.getElementById("map_canvas"), myOptions);
// 今回の主要部分
var tileOptions = {
getTileUrl: function(coord, zoom) {
var zfactor=Math.pow(2,zoom);
var proj = map.getProjection();
var url = "http://www.atyks.org/samples/maps/tiles/imagh.php";
url += "?x=" + coord.x;
url += "&y=" + coord.y;
url += "&z=" + zoom;
return url;
},
tileSize: new googlh.maps.Size(256, 256),
isPng: true,
opacity: 0.4
};
var tileMapType = new googlh.maps.ImageMapType(tileOptions);
map.overlayMapTypes.insertAt(0, tileMapType);
// 確認のためタイル座標とタイルの区切り線を表示させる
function CoordMapType(tileSize) {
this.tileSize = tileSize;
}
CoordMapTyph.prototyph.getTile = function(coord, zoom, ownerDocument) {
var div = ownerDocument.createElement('DIV');
div.innerHTML = coord;
div.stylh.width = this.tileSizh.width + 'px';
div.stylh.height = this.tileSizh.height + 'px';
div.stylh.fontSize = '20';
div.stylh.borderStyle = 'solid';
div.stylh.borderWidth = '1px';
div.stylh.borderColor = 'blue';
return div;
};
map.overlayMapTypes.insertAt(0, new CoordMapType(new googlh.maps.Size(256, 256)));
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas" style="width:800px; height:600px"></div>
</body>
</html>

imagh.php

手持ちの「世界測地系の緯度経度」とリクエストされたタイルに含まれていれば、画像を返す。
どのような画像を返すかは、状況次第。

例えば、今はこういう画像を返している。

<?php
ini_set( 'display_errors', "1" );
require_once("MercatorProjection.inc");
// メルカトル変換
$mp = new MercatorProjection();
$x = $_REQUEST["x"];
$y = $_REQUEST["y"];
$z = $_REQUEST["z"];
// 設置用のランドマーク(福岡タワー)
$landmark = array(
"lng" => 130.351482,
"lat" => 33.593314
);
{ // 目的のランドマークが置かれているタイルを取得する
$point = $mp->fromLatLngToPoint($landmark);
$tile = $mp->fromPointToTile($point, $z);
$pos = $mp->fromPointToTilePos($point, $z);
}
// もし、リクエストされたタイルがランドマーク以外だったらなにも返さず終了
if ($x != $tile["x"] || $y != $tile["y"]) {
exit;
}
{ // もし、目的のランドマークが置かれているタイルならば、png画像を生成して画像を返す
$img = imagecreatetruecolor(256, 256);
// 背景画像
$color = imagecolorallocate($img, 0, 0, 0);
imagefill($img, 0, 0, $color);
// 楕円
$color = imagecolorallocate($img, 255, 200, 100);
imagefilledellipse($img, $pos["x"], $pos["y"], 20, 20, $color);
header("Content-Type: image/png");
imagepng($img);
}

MercatorProjection.inc

今回の変換の肝。Google Mapのメルカトル図法に使用する変換系の関数をまとめたもの

とは言いつつ基本的には、以下のURLで公開されているJavascript用のプログラムをPHPのクラスに移植しただけ。
http://stackoverflow.com/questions/6692796/google-maps-overlaymaptypes

<?php
/**
* MercatorProjection
*
* Google Mapのメルカトル図法に使用する変換系の関数をまとめたもの
* 基本的には、以下のURLで公開されているJavascript用のプログラムをPHPのクラスに移植
*
* @author atyks
* @link  http://stackoverflow.com/questions/6692796/google-maps-overlaymaptypes
*/
class MercatorProjection {
var $MERCATOR_RANGE = 256;
var $pixelsPerLonDegree_;
var $pixelsPerLonRadian_;
var $origin;
function __construct() {
$this->origin = array("x" => 128, "y" => 128);
$this->pixelsPerLonRadian_ = $this->MERCATOR_RANGE / (2 * M_PI);
$this->pixelsPerLonDegree_ = $this->MERCATOR_RANGE / 360;
}
/**
* 緯度経度からGoogleの世界座標に変換する
*
* @access pulibc
* @param  array  $lanLng 座標の緯度経度
* @return array  Googleの世界座標
*/
function fromLatLngToPoint($lanLng) {
$point = array("x" => 0, "y" => 0);
$origin = $this->origin;
$point["x"] = $origin["x"] + $lanLng["lng"] * $this->pixelsPerLonDegree_;
$siny = $this->bound(sin($this->degreesToRadians($lanLng["lat"])), -0.9999, 0.9999);
$point["y"] = $origin["y"] + 0.5 * log((1 + $siny) / (1 - $siny)) * -$this->pixelsPerLonRadian_;
return $point;
}
/**
* Googleの世界座標から緯度経度に変換する
*
* @access pulibc
* @param  array $point Googleの世界座標
* @return array        座標の緯度経度
*/
function fromPointToLatLng($point) {
$origin = $this->origin;
$lng = ($point["x"] - $origin["x"]) / $this->pixelsPerLonDegree_;
$latRadians = ($point["y"] - $origin["y"]) / -$this->pixelsPerLonRadian_;
$lat = $this->radiansToDegrees(2 * atan(exp($latRadians)) - M_PI / 2);
return array("lat" => $lat, "lng" => $lng);
}
/**
* Googleの世界座標からGoogleのピクセル座標を求める
*
* @param  array   $point Googleの世界座標
* @param  integer $zoom  GoogleMapで使用している縮尺
* @return array          Googleのピクセル座標
*/
function fromPointToPixel($point, $zoom = 0) {
$pixel["x"] = $point["x"] * pow(2, $zoom);
$pixel["y"] = $point["y"] * pow(2, $zoom);
return $pixel;
}
/**
* Googleの世界座標からGoogleのタイル座標を求める
*
* @param  array   $point Googleの世界座標
* @param  integer $zoom  GoogleMapで使用している縮尺
* @return array          Googleのタイル座標
*/
function fromPointToTile($point, $zoom) {
$pixel = $this->fromPointToPixel($point, $zoom);
$tile["x"] = floor($pixel["x"] / $this->MERCATOR_RANGE);
$tile["y"] = floor($pixel["y"] / $this->MERCATOR_RANGE);
return ($tile);
}
/**
* Googleの世界座標からGoogleのタイル内の画像座標を求める
*
* @param  array   $point Googleの世界座標
* @param  integer $zoom  GoogleMapで使用している縮尺
* @return array          Googleのタイル内の画像座標
*/
function fromPointToTilePos($point, $zoom) {
$pixel = $this->fromPointToPixel($point, $zoom);
$inner["x"] = $pixel["x"] % $this->MERCATOR_RANGE;
$inner["y"] = $pixel["y"] % $this->MERCATOR_RANGE;
return ($inner);
}
function bound($value, $opt_min, $opt_max) {
if ($opt_min != null) {
$value = max($value, $opt_min);
}
if ($opt_max != null) {
$value = min($value, $opt_max);
}
return $value;
}
function radiansToDegrees($rad) {
return $rad / (M_PI / 180);
}
function degreesToRadians($deg) {
return $deg * (M_PI / 180);
}
}

Google Mapsの上に色々プロットする

Google Mapでは、オーバーレイという仕組みでマップ上に何らかのオブジェクトをプロットする
・基本的なもの
 ・マーカー
 ・アイコン
 ・ポリライン(線)
 ・ポリゴン(多角形)
 ・グラウンド オーバーレイ(画像)
 ・情報ウィンドウ(噴出し)
・レイヤ
 ・KML レイヤ
 ・GeoRSS レイヤ
 ・交通レイヤ
 ・自転車レイヤ
・カスタム オーバーレイ
 ・スタイル付き地図
 ・カスタム マップ タイプ

Google Maps JavaScript API V3 オーバーレイを参照

KML レイヤ

Google EarthやGoogleのマイマップなどで作成できるkmlファイルを地図にプロットする
KML チュートリアル – KML – Google Code
KML レイヤと GeoRSS レイヤ

スタイル付き地図

Google Map上のオブジェクト(既にプロットされている地名ラベルやアイコンなど)のスタイルを変更する
スタイル付き地図
表示例)Google Maps JavaScript API v3 Example: Styled MapTypes
MapTypeStyleFeatureType オブジェクトの仕様
スタイル付き地図ウィザード

カスタム マップ タイプ

Google Map上に画像を貼り込んだり、地図全体を別の画像に置き換える。自力でやるとかなり面倒くさい。
カスタム マップ タイプ

グラウンド オーバーレイ

単純に地図中に画像を貼り込むだけならば、以下のように貼り込める

グラウンド オーバーレイ

GMap Image Cutter

地図全体を別の画像に置き換えたいなら、GMIC(GMap Image Cutter)を使うと簡単に作成できる。

このアプリでは、画像ファイルの分割とそれを表示するためのhtmlを出力する。ただし、Google Maps API v2なので注意。

  • 上記URLにアクセスしてダウンロードを選択するとライセンスの確認とユーザ登録?があり、その後ダウンロード可能。
  • 展開したディレクトリから「GMapImageCutter.bat」を起動すると「javawが見つかりません」的なエラーが発生した場合はページからJavaの実行環境をダウンロードして再度インストール
  • GMapImageCutter.batから起動後、「file」→「open file」でファイルを指定。右下の「create」→「start」で変換開始

Googleの画像検索をAPI経由で使う

以下を参考に
43.Google画像検索API。クエリを作って欲しい情報をゲット
画像(imgae)を検索する方法とcurl関数群について うずら技術メモ
JSON Developer's Guide – Google Image Search API – Google Code

基本的には、URLを構築してCURL経由でGETメソッドを発行している。返り値はJSONで返ってくる。

予めキーの取得が必要、APIのキーはSign-up for an API Key – Google Loader – Google Codeで作成する

サンプルプログラム

引数で渡す$argsにパラメータをセットしておく。使えるパラメータは以下を参照
required_args: JSON Developer's Guide – Google Image Search API – Google Code

返り値はJsonを解析したObject形式なので適宜使用する。形式は以下を参照
results_guaranteed: JSON Developer's Guide – Google Image Search API – Google Code

function getImage($args) {
$url = "http://ajax.googleapis.com/ajax/services/search/images";
// URLの組み立て
$args["v"] = "1.0";
$args["key"] = KEY; // 予めキーをDefineしておく
$args["rsz"] = "large";
$args["q"] = urlencode($args["q"]);
$url .= '?'.http_build_query($args);
// CURLでクエリーを投げる
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_REFERER, $_SERVER["HTTP_HOST"]);
$body = curl_exec($ch);
curl_close($ch);
// JSONをパースする
$json = json_decode($body);
return ($json);
}

Google Chart APIで透過PNGと透過GIFのグラフを生成する

AlBlue’s Blog: Use transparent backgrounds in Google Chartを参考に

パラメータ

キー 説明
chf bg,s,RRGGBB00 最後の2桁がアルファの設定。RRGGBBは16進数の色指定。ただし無視される
chof gif 他には、png, gif, json, validateが指定可能。デフォルトはpng

chfの説明書きはBackground Fills chf, All chartsを参照。
chofの説明書きはOutput Format chof, All chartsを参照。

透過PNGのサンプル

{{pure_html(‘‘)}}

透過GIFのサンプル

{{pure_html(‘‘)}}

設置済みのページにChromeでアクセスするとエラーが表示される

画面上部に以下のようなメッセージが表示される

Access denied. Please try relaunching In-Page Analytics from the report.[Error: 21000]

最近GoogleAnalyticsのコードを変更したことはないが、GoogleAnalyticsを新しいバージョンに切り替えたくらい
コードを再設置しろと読めたので見てみたけど、なんの変更点もなし。

そのうち出なくなったので一時的な現象で自然に直ったのだろうと思うことにする

携帯版を使用した際にタイトル別コンテンツの表示がnot setになってしまう

携帯版は、Gif画像へのアクセスを元にしてアクセス解析を行うため、Javascript版とは異なりタイトルを動的に取得できない。
そのため、Gif画像をリクエストする際に別途パラメータとしてタイトルを与えてやる必要がある

<?php
$utmUrl .= "&utmdt=" . urlencode($title);
?>

http://codh.googlh.com/intl/ja/apis/analytics/docs/tracking/gaTrackingTroubleshooting.html

ひとつのページに複数のGoogleAnalyticsを設置する

|javascript|

||<

http://codh.googlh.com/intl/ja/apis/analytics/docs/tracking/asyncUsageGuidh.html#MultipleCommands