本サイトは、佐世保市内の在宅医療に対応可能な薬局を検索し、医療機関や患者家族が適切な薬局を選ぶための支援を目的としています。地域の薬局と医療機関の連携を強化し、在宅医療の質の向上を目指します。
本サイトは、Googleスプレッドシートから薬局の情報を取得し、以下のように表示しています:
https://docs.google.com/spreadsheets/d/1OjHsMEOejAZyLraH6RtkPmVmny0d8z1IPAJuZ6h_wh4/gviz/tq?tqx=out:json
)からJSON形式でデータを取得。https://www.google.com/maps/dir/
)を使用し、患者住所から薬局までの経路をブラウザで表示(API不要)。以下はGoogle Maps APIを使用した場合のコード例(index.html
の変更点):
<head>
<!-- Google Maps API -->
<script async src="https://maps.googleapis.com/maps/api/js?key=[YOUR_API_KEY]&libraries=places,directions&callback=initMap"></script>
<style>
#map { height: 200px; width: 100%; margin-top: 1em; }
</style>
</head>
<body>
<!-- 地図コンテナ -->
<div id="map" class="mb-4"></div>
<!-- 既存のコンテンツ -->
<script>
let map;
let geocoder;
let directionsService;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: { lat: 33.167, lng: 129.725 }, // 佐世保市中心
zoom: 12
});
geocoder = new google.maps.Geocoder();
directionsService = new google.maps.DirectionsService();
// Places APIで住所補完
const autocomplete = new google.maps.places.Autocomplete(
document.getElementById('patientAddress'),
{ componentRestrictions: { country: 'jp' } }
);
autocomplete.addListener('place_changed', () => {
const place = autocomplete.getPlace();
if (place.geometry) {
document.getElementById('patientAddress').value = place.formatted_address;
renderList();
}
});
}
async function createPharmacyCard(pharmacy, patientAddress) {
const card = document.createElement('div');
card.classList.add('card');
let routeLink = \`<a href="https://www.google.com/maps/search/?api=1&query=\${encodeURIComponent(pharmacy.address)}" target="_blank" class="btn btn-primary btn-sm route-button" onclick="event.stopPropagation();">経路を表示</a>\`;
let distanceInfo = '';
if (patientAddress) {
const normalizedPatientAddress = normalizeAddress(patientAddress);
if (normalizedPatientAddress) {
routeLink = \`<a href="https://www.google.com/maps/dir/?api=1&origin=\${encodeURIComponent(normalizedPatientAddress)}&destination=\${encodeURIComponent(pharmacy.address)}" target="_blank" class="btn btn-primary btn-sm route-button" onclick="event.stopPropagation();">経路を表示</a>\`;
// 距離計算
try {
const response = await new Promise((resolve, reject) => {
directionsService.route({
origin: normalizedPatientAddress,
destination: pharmacy.address,
travelMode: google.maps.TravelMode.DRIVING
}, (result, status) => {
if (status === google.maps.DirectionsStatus.OK) {
resolve(result);
} else {
reject(status);
}
});
});
const distance = response.routes[0].legs[0].distance.text;
const duration = response.routes[0].legs[0].duration.text;
distanceInfo = \`<div class="distance">距離: \${distance}(車で\${duration})</div>\`;
} catch (error) {
console.error('距離計算エラー:', error);
}
} else {
routeLink = \`<a class="btn btn-secondary btn-sm route-button disabled" role="button" aria-disabled="true" onclick="event.stopPropagation();">経路を表示(住所無効)</a>\`;
}
}
// 以下、既存のカードHTML(省略)
const collapseId = \`collapse-\${pharmacy.name.replace(/\s+/g, '-')}\`;
card.innerHTML = \`
<div class="card-header" data-bs-toggle="collapse" data-bs-target="#\${collapseId}">
<!-- カードヘッダー内容 -->
</div>
<div id="\${collapseId}" class="collapse">
<div class="card-body">
\${distanceInfo}
<!-- 既存のカードボディ内容 -->
</div>
</div>
\`;
return card;
}
</script>
上記コードは、Google Maps APIキー([YOUR_API_KEY]
)をGoogle Cloud Consoleで取得し、設定する必要があります。詳細はGoogle Maps Platformを参照してください。
薬局登録フォームで入力された住所(例:「長崎県佐世保市天神1丁目」)から、自動で緯度・経度を取得し、スプレッドシートの列AJ(緯度)、列AK(経度)に保存する方法を以下に説明します。Google Apps Script (GAS) を使用し、Google Maps サービス(APIキー不要)または Google Maps Geocoding API(APIキー必要)を活用します。
onFormSubmit
。以下のコードは、Google Apps Script の Maps サービスを使用し、住所から緯度・経度を取得します。小規模な利用(例:月50件)に適しています。
function onFormSubmit(e) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const lastRow = sheet.getLastRow();
const address = sheet.getRange(lastRow, 5).getValue(); // 列E(住所)
if (address) {
try {
const response = Maps.newGeocoder().geocode(address);
if (response.results.length > 0) {
const { lat, lng } = response.results[0].geometry.location;
sheet.getRange(lastRow, 36).setValue(lat); // 列AJ(緯度)
sheet.getRange(lastRow, 37).setValue(lng); // 列AK(経度)
} else {
sheet.getRange(lastRow, 36).setValue('取得失敗');
sheet.getRange(lastRow, 37).setValue('取得失敗');
}
} catch (error) {
sheet.getRange(lastRow, 36).setValue('エラー');
sheet.getRange(lastRow, 37).setValue(error.message);
}
}
}
高頻度または高精度が必要な場合、Google Maps Geocoding API を使用します。Google Cloud Console で API キーを取得してください(詳細)。コスト:$5/1000リクエスト、無料枠 $200/月。
function onFormSubmit(e) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const lastRow = sheet.getLastRow();
const address = sheet.getRange(lastRow, 5).getValue(); // 列E(住所)
const apiKey = 'YOUR_API_KEY'; // Google Cloud Console で取得
const url = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(address)}&key=${apiKey}`;
try {
const response = UrlFetchApp.fetch(url);
const json = JSON.parse(response.getContentText());
if (json.status === 'OK' && json.results.length > 0) {
const { lat, lng } = json.results[0].geometry.location;
sheet.getRange(lastRow, 36).setValue(lat); // 列AJ(緯度)
sheet.getRange(lastRow, 37).setValue(lng); // 列AK(経度)
} else {
sheet.getRange(lastRow, 36).setValue('取得失敗');
sheet.getRange(lastRow, 37).setValue(json.status);
}
} catch (error) {
sheet.getRange(lastRow, 36).setValue('エラー');
sheet.getRange(lastRow, 37).setValue(error.message);
}
}
無料で利用可能ですが、1秒1リクエストの制限があります。以下は Nominatim を使用したコード例です。
function onFormSubmit(e) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const lastRow = sheet.getLastRow();
const address = sheet.getRange(lastRow, 5).getValue(); // 列E(住所)
const url = `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(address)}&countrycodes=JP&limit=1`;
try {
const response = UrlFetchApp.fetch(url, { headers: { 'User-Agent': 'SaseboZaitakuPharmacyMatch/1.0' } });
const data = JSON.parse(response.getContentText());
if (data.length > 0) {
const { lat, lon } = data[0];
sheet.getRange(lastRow, 36).setValue(lat); // 列AJ(緯度)
sheet.getRange(lastRow, 37).setValue(lon); // 列AK(経度)
} else {
sheet.getRange(lastRow, 36).setValue('取得失敗');
sheet.getRange(lastRow, 37).setValue('取得失敗');
}
Utilities.sleep(1000); // 1秒1リクエスト制限
} catch (error) {
sheet.getRange(lastRow, 36).setValue('エラー');
sheet.getRange(lastRow, 37).setValue(error.message);
}
}
Utilities.sleep(1000)
必須。詳細は Google Maps Platform または Nominatim を参照してください。