Help us understand the problem. What is going on with this article?

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

動機付け

こちらのサイトを作りました。コロナウイルスに関する呟きを集計、可視化します。
corona-virus-trend - コロナウイルス情報を分析・可視化

呟かれている地名の頻度に応じて地図上にマッピングしたいと思ったのがきっかけです。
地図

前提条件

  • GCPでAPIキーを取得します。
  • サーバサイドスクリプト(PHP)が稼働するサーバを持っている必要があります。

ドキュメント

こちらに書いてあることがほぼ全てですが、いくつか詰まったところもありました。
Developer Guide  |  Maps Static API  |  Google Developers

カスタムアイコンのサイズ変更

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

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

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

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してから地図を呼び出しています。

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\">");
?>

参考資料

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした