Google Maps Static APIでサイズの異なるカスタムアイコンを配置する

# 動機付け
こちらのサイトを作りました。コロナウイルスに関する呟きを集計、可視化します。
[corona-virus-trend - コロナウイルス情報を分析・可視化](http://corona-virus-trend.com/)

呟かれている地名の頻度に応じて地図上にマッピングしたいと思ったのがきっかけです。
![地図](https://maps.googleapis.com/maps/api/staticmap?size=640x640&language=ja&maptype=roadmap&key=AIzaSyAitg4EiBYdUnX-5zDrDhEbMtvBF4H2UO4&markers=anchor:center|icon:http://corona-virus-trend.com/capture/resize_icon.php?size=33|South Korea&markers=anchor:center|icon:http://corona-virus-trend.com/capture/resize_icon.php?size=33|China&markers=anchor:center|icon:http://corona-virus-trend.com/capture/resize_icon.php?size=24.666666666667|Tokyo, Japan&markers=anchor:center|icon:http://corona-virus-trend.com/capture/resize_icon.php?size=24.666666666667|Nagoya, Aichi, Japan&markers=anchor:center|icon:http://corona-virus-trend.com/capture/resize_icon.php?size=24.666666666667|Hokkaido, Japan&markers=anchor:center|icon:http://corona-virus-trend.com/capture/resize_icon.php?size=16.333333333333|Chiba, Japan&markers=anchor:center|icon:http://corona-virus-trend.com/capture/resize_icon.php?size=16.333333333333|Osaka, Japan&markers=anchor:center|icon:http://corona-virus-trend.com/capture/resize_icon.php?size=16.333333333333|United States&markers=anchor:center|icon:http://corona-virus-trend.com/capture/resize_icon.php?size=16.333333333333|Wuhan, Hubei, China&markers=anchor:center|icon:http://corona-virus-trend.com/capture/resize_icon.php?size=8|Ebetsu, Hokkaido, Japan)
# 前提条件
* GCPでAPIキーを取得します。
* サーバサイドスクリプト(PHP)が稼働するサーバを持っている必要があります。

# ドキュメント
こちらに書いてあることがほぼ全てですが、いくつか詰まったところもありました。
[Developer Guide  |  Maps Static API  |  Google Developers](https://developers.google.com/maps/documentation/maps-static/dev-guide#Imagesizes)

# カスタムアイコンのサイズ変更
サーバ上に画像を準備して以下の書式に合わせてURLを組み立てればいいのですが、自分はこのアイコンのサイズを地名のキーワードの頻度に合わせて変化させたかったのです。
```markers=icon:URLofIcon|markerLocation```

それぞれのサイズの画像を準備するという手もありますが、自分は動的にアイコンのサイズを変えることにしました。PHPを使っているのでこちらを参考にさせていただきました。ブラウザに直接出力しています。marker.pngは元画像、適宜パスを変えてください。
[PHP: GDで画像のサイズ変更やサムネイル生成のやりかた - Qiita](https://qiita.com/suin/items/b01eebc05209dba0eb3e)

```php:resize.php
<?php
header('Content-Type: image/png');

/**
 * 画像のサイズを変形して保存する
 * @param string $srcPath
 * @param int $width
 * @param int $height
 */
function transform_image_size($srcPath, $width, $height)
{
    list($originalWidth, $originalHeight, $type) = getimagesize($srcPath);
    switch ($type) {
        case IMAGETYPE_JPEG:
            $source = imagecreatefromjpeg($srcPath);
            break;
        case IMAGETYPE_PNG:
            $source = imagecreatefrompng($srcPath);
            break;
        case IMAGETYPE_GIF:
            $source = imagecreatefromgif($srcPath);
            break;
        default:
            throw new RuntimeException("サポートしていない画像形式です: $type");
    }

    $canvas = imagecreatetruecolor($width, $height);
    //ブレンドモードを無効にする
    imagealphablending($canvas, false);
    //完全なアルファチャネル情報を保存するフラグをonにする
    imagesavealpha($canvas, true);

    imagecopyresampled($canvas, $source, 0, 0, 0, 0, $width, $height, $originalWidth, $originalHeight);

    imagepng($canvas, null);

    imagedestroy($source);
    imagedestroy($canvas);
}

$size = $_GET['size'];
transform_image_size('marker.png', $size, $size);
?>
```
# カスタムアイコンの呼び出し数制限
呼び出すときに、時々カスタムアイコンではなくデフォルトアイコンになってどうしてだろうと数日悩みました。結局最初のドキュメントをチキンと読んでおくべきだったということです。一度の呼び出しで5種類までのカスタムアイコンしか呼べないということです。
[Google Maps Static Map - Custom icons limit - Stack Overflow](https://stackoverflow.com/questions/5024735/google-maps-static-map-custom-icons-limit)
> Static Maps service allows up to five unique custom icons per request. 
> Note that each of these unique icons may be used multiple times within the static map.

ということで、アイコンの種類数を5種類に限定するロジックを組み込みました。最大値、最小値を取得してからその間の区間を3等分。以下のコードでは、$itemsに地名と頻度が格納されていて、Geocodingしてから地図を呼び出しています。

```php:static_map.php
<?php
// put the data in the array
$data_arr = array();
            
foreach ($items as $address => $value) {
  // url encode the address
  $address = urlencode($address);
     
  // google map geocode api url
  $url = "https://maps.googleapis.com/maps/api/geocode/json?address={$address}&key=APIKEY";
 
  // get the json response
  $resp_json = file_get_contents($url);

  // decode the json
  $resp = json_decode($resp_json, true);
 
  // response status will be 'OK', if able to geocode given address 
    if($resp['status']=='OK'){
 
        // get the important data
        $lat = isset($resp['results'][0]['geometry']['location']['lat']) ? $resp['results'][0]['geometry']['location']['lat'] : "";
        $long = isset($resp['results'][0]['geometry']['location']['lng']) ? $resp['results'][0]['geometry']['location']['lng'] : "";
        $formatted_address = isset($resp['results'][0]['formatted_address']) ? $resp['results'][0]['formatted_address'] : "";
         
        // verify if data is complete
        if($lat && $long && $formatted_address){

            array_push(
                $data_arr, 
                    array($lat, 
                    $long, 
                    $formatted_address,
                    $value)
                );
             
       }
    }
}

// size mapping
$min = $data_arr[0][3];
$max = $data_arr[0][3];
foreach ($data_arr as $item) {
  if($min > $item[3] ) $min = $item[3];
  if($min < $item[3] ) $max = $item[3];
}

$range = $max - $min;
$portion = $range / 3;

// url building
$base_url = 'https://maps.googleapis.com/maps/api/staticmap?size=640x640&language=ja&maptype=roadmap&key=APIKEY';

$marker_array = array();
foreach ($data_arr as $item) {

  if($item[3] == $min)
    $size = $min;
  else if($item[3] > $min && $item[3] <= $min + $portion)
    $size = $min + $portion;
  else if($item[3] > $min + $portion && $item[3] <= $min + $portion * 2)
    $size = $min + $portion * 2;
  else if($item[3] > $min + $portion * 2 && $item[3] <= $min + $portion * 3)
    $size = $min + $portion * 3;
  else if($item[3] == $max)
    $size = $max;
  
  $marker_url = urldecode("http://corona-virus-trend.com/xxx/resize_icon.php?size={$size}");
  $marker_para = "markers=anchor:center|icon:{$marker_url}|{$item[2]}";
  array_push($marker_array, $marker_para);
}

$marker_para_str = join("&", $marker_array);
$map_url = $base_url . "&" . $marker_para_str;

print("<img src=\"$map_url\">");
?>
```
# 参考資料
* [Developer Guide  |  Maps Static API  |  Google Developers](https://developers.google.com/maps/documentation/maps-static/dev-guide#Imagesizes)
* [PHP: GDで画像のサイズ変更やサムネイル生成のやりかた - Qiita](https://qiita.com/suin/items/b01eebc05209dba0eb3e)
* [Google Maps Geocoding Example with PHP](https://www.codeofaninja.com/2014/06/google-maps-geocoding-example-php.html)
* [Google Maps Static Map - Custom icons limit - Stack Overflow](https://stackoverflow.com/questions/5024735/google-maps-static-map-custom-icons-limit)