MENU
  • ホーム
  • サービス
  • 記事一覧
  • 問い合わせ
プログラミングやサーバー設定など様々な内容を紹介しています。
HIROTRONの部屋
  • ホーム
  • サービス
  • 記事一覧
  • 問い合わせ
HIROTRONの部屋
  • ホーム
  • サービス
  • 記事一覧
  • 問い合わせ
  1. ホーム
  2. Django
  3. 第3話:地図の中にスタンプ!?Google Maps × Django管理画面の作成

第3話:地図の中にスタンプ!?Google Maps × Django管理画面の作成

2025 6/25
Django LINE_Messaging_API さどんでこプロジェクト
2025年6月22日2025年6月25日

私は、友達の紹介でさどんでこプロジェクトのIT担当として様々システム構築などを行っています。今回、スタンプラリー作成でかなり大変だったということから、開発秘話をブログにまとめてみました。興味ある方ぜひ御覧ください。

Sadondeko Project
佐渡を楽しむ デジタルスタンプラリー – さどんでこプロジェクト 佐渡の伝統文化「鬼太鼓」をテーマにしたデジタルスタンプラリーです!両津港をスタート地点に、佐渡金山や大野亀などの主要観光地を巡りながら、各地で鬼太鼓スタンプを集…

第1,2話は以下です、合わせてお読みください。

あわせて読みたい
第1話:WordPressじゃ物足りない!?LINE✕鬼太鼓スタンプラリー開発のはじまり 私は、友達の紹介でさどんでこプロジェクトのIT担当として様々システム構築などを行っています。今回、スタンプラリー作成でかなり大変だったということから、開発秘話…
あわせて読みたい
第2話:画像に仕込む魔法!LINEイメージマップとスタンプの格闘記 私は、友達の紹介でさどんでこプロジェクトのIT担当として様々システム構築などを行っています。今回、スタンプラリー作成でかなり大変だったということから、開発秘話…

目次

今回のテーマ

  • スタンプラリーの“スポット”情報を管理するためのDjango管理画面
  • Google Mapsと連携して地図上で位置を登録・編集する仕組み
  • スタンプの近接や重複をチェックするUIの工夫

スタンプの緯度・経度を簡単に設定できるUIを目指して

LINEでスタンプを押してもらうには、「この場所に来たらスタンプを獲得できる」=位置情報の判定が必要です。

つまり、「スタンプごとに緯度・経度を持たせる必要がある」ということ。

ですが、管理者(多くは非エンジニア)がそれを扱うには、Djangoの管理画面で数値を直接入力させるのではなく、地図上で直感的にポチッと登録できるUIが求められました。


Google Maps × Django 管理画面をカスタム実装

そこで導入したのが、Google Maps JavaScript API を使った Django 管理画面のカスタマイズ。

実装ポイント

  1. Djangoモデルに緯度(latitude)・経度(longitude)・有効範囲(radius_m)フィールドを追加
  2. 管理画面テンプレートでGoogle Mapsを読み込み、地図を表示
  3. マーカーをクリックで移動 → 緯度経度を即座にフィールドへ反映
  4. 保存時にモデルに反映
class StampSpot(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    latitude = models.FloatField()
    longitude = models.FloatField()
    radius_m = models.FloatField(default=100)
    image = models.ImageField(upload_to="stamps/", blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)

① input要素の取得と初期値の設定

const latInput = document.getElementById("id_latitude");
const lngInput = document.getElementById("id_longitude");
const radiusInput = document.getElementById("id_radius_m");

これはDjangoモデルのフィールドに対応するinput要素(<input id=”id_latitude”>など)を取得しています。

const initialLat = parseFloat(latInput.value) || 38.2;

ユーザーが未入力の場合でも地図が出るようにデフォルト値(佐渡の中心付近)を設定。

② Google Map & マーカー & 円を描画

const map = new google.maps.Map(...);
const marker = new google.maps.Marker(...);
const circle = new google.maps.Circle(...);
  • markerはドラッグ可能
  • circleはスタンプの有効範囲を視覚化
  • circle.centerとmarker.positionは連動させている

③ 地図クリック → マーカー&円を移動

map.addListener("click", (e) => {
  marker.setPosition(e.latLng);
  circle.setCenter(e.latLng);
  updateInputs(e.latLng);
});
  • 管理者が地図をクリックすればその位置が「スポットの中心」になる
  • クリックするだけでinput欄の緯度・経度もリアルタイムで更新

④ マーカーをドラッグ → 円の位置を追従

marker.addListener("dragend", (e) => {
  circle.setCenter(e.latLng);
  updateInputs(e.latLng);
});
  • マーカーを直接動かしても、その動きをcircleとinput欄に反映
  • ユーザーがどちらの操作でも違和感なく使える

⑤ 半径の変更 → 円のサイズ更新

radiusInput.addEventListener("input", () => {
  const newRadius = parseFloat(radiusInput.value);
  if (!isNaN(newRadius)) {
    circle.setRadius(newRadius);
  }
});
  • 半径(radius_m)の数値を入力すれば、円のサイズも即時更新
  • フォーム側と地図が双方向に連動している

実際の完成した管理画面

  • 地図を見ながら「このへん」と直感的にクリック
  • 有効半径も表示されるので調整しやすい
  • 座標入力欄に数値がリアルタイムで反映

重複チェックも大事な機能だった

鬼太鼓スタンプラリーには複数のコースが存在し、同じスタンプが別コースにも登場する構造があります。

そのため、同じスポットが重複登録されないよう、スタンプごとの近接チェックも実装しました。

チェック機能の仕組み

  • スタンプ登録時、一定距離以内に同じIDのスポットがないか自動チェック
  • 色付きマーカーで近接スポットを可視化
  • 複数スポットが重なると警告を表示

スタンプスポットを一覧で表示する画面を追加し、それぞれの範囲を表示、範囲に重複が無いか確認が簡単になった


画像合成の土台としての座標管理

次にスタンプカードの上にスタンプを合成するに当たって、スタンプカード上のスタンプの位置を記録する必要があります。それを管理画面でマウスで操作することで簡単に設定できるようにしました。

直感的なスタンプ配置ができる管理画面

管理画面の中には、以下のような機能を詰め込みました:

  • 拡大率(倍率)をコースごとに設定・反映
  • スタンプカード画像をベースに表示
  • プルダウンから追加したいスタンプ(スポット)を選択
  • 画像上をクリックしてスタンプを追加
  • スタンプをドラッグで移動、右クリックで削除
<img id="map-image" src="{{ course.image.url }}" />
<div class="marker" data-x="120" data-y="340" data-spot-id="7"></div>


JavaScriptで画像の縮尺に応じてマーカー位置をリアルタイムで反映。レスポンシブにも対応し、スマホでも操作可能な設計です。

管理画面で設定した内容:

現在のスタンプの位置を確認できる

マウスでスタンプは移動できる、位置は即時保存される

技術的ポイント(JS + Django連携)

成功・失敗をトースト通知(Bootstrap風)

画像の 実サイズと表示サイズの比率(displayScale) を取得し、ピクセル位置を変換

新規スタンプはクリック座標をPOST

移動時はPATCH、削除時はDELETEでAPI呼び出し

const displayScale = image.clientWidth / image.naturalWidth;
const x = (e.clientX - rect.left) / displayScale;
const y = (e.clientY - rect.top) / displayScale;


スタンプが表示されるサイズも 40 * 拡大率 * displayScale のように動的に設定され、すべてのスタンプが一貫した見た目になるよう調整しています。


管理画面の完成!

これで、スタンプの登録、スタンプの位置情報の登録、スタンプカードの登録、スタンプカード上のスタンプの位置の登録ができる管理画面が完成しました!

管理画面トップ

スタンプスポット一覧

スタンプコース一覧


次回予告:位置情報とLINEの連携!LIFFでスタンプを獲得する仕組み

いよいよ、LIFF(LINE Front-end Framework) の登場です。

  • ユーザーが現在地をLINE内で送信できる仕組み
  • 指定エリアに入ったときにだけスタンプを獲得できるようにする処理
  • 合言葉の発行とLINE Botとのやり取り

“LINEでスタンプを獲得できる仕組み”の全貌を解説します!

あわせて読みたい
第4話:位置情報でスタンプ獲得!LIFFとLINE Botの連携の裏側 私は、友達の紹介でさどんでこプロジェクトのIT担当として様々システム構築などを行っています。今回、スタンプラリー作成でかなり大変だったということから、開発秘話…
Sadondeko Project
佐渡を楽しむ デジタルスタンプラリー – さどんでこプロジェクト 佐渡の伝統文化「鬼太鼓」をテーマにしたデジタルスタンプラリーです!両津港をスタート地点に、佐渡金山や大野亀などの主要観光地を巡りながら、各地で鬼太鼓スタンプを集…
LINE友達登録でスタンプラリー開始!
Django LINE_Messaging_API さどんでこプロジェクト
Django Google Map API Javascript LINE LINE Messaging API さどんでこプロジェクト
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
  • 第2話:画像に仕込む魔法!LINEイメージマップとスタンプの格闘記
  • 第4話:位置情報でスタンプ獲得!LIFFとLINE Botの連携の裏側

この記事を書いた人

hiroto121022のアバター hiroto121022

医学生でありながら、さどんでこプロジェクトのITリーダーを務めるフルスタック開発者。LINE BotやGPS連携スタンプラリー、NFT販売サイトなどをすべて独学で開発。使用言語はPython、Typescript、Javascript。Django、Next.js、Reactなどのフレームワークを駆使し、サーバー構築・デプロイ・SSL対応まで一貫して担当。AIによるアートのアニメーション化にも取り組み、伝統文化とテクノロジーを融合させた新しい地域体験の創出に挑戦している。

関連記事

  • Django ✕ LINE Messaging APIでローディングアニメーションを出す方法
    2025年6月25日
  • 第4話:位置情報でスタンプ獲得!LIFFとLINE Botの連携の裏側
    2025年6月22日
  • 第2話:画像に仕込む魔法!LINEイメージマップとスタンプの格闘記
    2025年6月22日
  • 第1話:WordPressじゃ物足りない!?LINE✕鬼太鼓スタンプラリー開発のはじまり
    2025年6月22日

コメント

コメント一覧 (1件)

  • LINE API × 鬼太鼓スタンプラリー誕生秘話②|イメージマップとスタンプ処理 - HIROTRONの部屋 より:
    2025年6月22日 8:53 PM

    […] LINE API × 鬼太鼓スタンプラリー誕生秘話③ 座標管理とDjango管理画面 – … […]

    返信

コメントする コメントをキャンセル

hiroto121022
医学生でありながら、さどんでこプロジェクトのITリーダーを務めるフルスタック開発者。LINE BotやGPS連携スタンプラリー、NFT販売サイトなどをすべて独学で開発。使用言語はPython、Typescript、Javascript。Django、Next.js、Reactなどのフレームワークを駆使し、サーバー構築・デプロイ・SSL対応まで一貫して担当。
GitHub
新着記事
  • Django ✕ LINE Messaging APIでローディングアニメーションを出す方法
  • 第4話:位置情報でスタンプ獲得!LIFFとLINE Botの連携の裏側
  • 第3話:地図の中にスタンプ!?Google Maps × Django管理画面の作成
  • 第2話:画像に仕込む魔法!LINEイメージマップとスタンプの格闘記
  • 第1話:WordPressじゃ物足りない!?LINE✕鬼太鼓スタンプラリー開発のはじまり

© HIROTRONの部屋.

目次