Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions app/assets/images/onsen.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
90 changes: 90 additions & 0 deletions app/javascript/controllers/form_map_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { Controller } from "@hotwired/stimulus"
import L from "leaflet"

// Connects to data-controller="form-map"
export default class extends Controller {
static targets = ["container", "latitudeInput", "longitudeInput"]

connect() {
this.currentMarker = null;

// 地図の初期化
this.map = L.map(this.containerTarget).setView([35.468, 133.0483], 11.5);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(this.map);

// フォームに初期値があればピンを立てる
if (this.hasLatitudeInputTarget && this.hasLongitudeInputTarget && this.latitudeInputTarget.value && this.longitudeInputTarget.value) {
this.updateMarkerAndInputs(this.latitudeInputTarget.value, this.longitudeInputTarget.value);
}

// マップクリック時のイベントリスナー
this.map.on("click", (e) => {
const { lat, lng } = e.latlng;
this.updateMarkerAndInputs(lat, lng);
});
}

// マーカーを更新し、フォームの値を自動入力
updateMarkerAndInputs(lat, lng) {
this.removeMarker(); // 既存のピンを削除

const latlng = [lat, lng];
this.currentMarker = L.marker(latlng).addTo(this.map)
.bindPopup(`緯度: ${lat.toFixed(5)}<br>経度: ${lng.toFixed(5)}`)
.openPopup();

this.map.setView(latlng, this.map.getZoom());
this.latitudeInputTarget.value = lat.toFixed(5);
this.longitudeInputTarget.value = lng.toFixed(5);
}

// 既存のピンを削除する
removeMarker() {
if (this.currentMarker) {
this.map.removeLayer(this.currentMarker);
}
}

// フォームの入力値からマーカーを更新
updateMarkerFromInput() {
const lat = parseFloat(this.latitudeInputTarget.value);
const lng = parseFloat(this.longitudeInputTarget.value);

// 有効な数値であることを確認
if (!isNaN(lat) && !isNaN(lng)) {
this.updateMarkerAndInputs(lat, lng);
}
}

/**
* 現在地を取得し、地図とフォームを更新する
*/
locate() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
const lat = position.coords.latitude;
const lng = position.coords.longitude;
this.updateMarkerAndInputs(lat, lng);
},
(error) => {
console.error("現在地の取得に失敗しました: ", error);
alert("現在地の取得に失敗しました。ブラウザの設定をご確認ください。");
}
);
} else {
alert("お使いのブラウザは現在地の取得に対応していません。");
}
}

// 切断時の処理
disconnect() {
if (this.map) {
this.map.remove();
this.map = null;
}
}
}
99 changes: 99 additions & 0 deletions app/javascript/controllers/index_map_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { Controller } from "@hotwired/stimulus"
import L from "leaflet"

// Connects to data-controller="index-map"
export default class extends Controller {
static targets = ["container"]
static values = { photoSpots: Array }

connect() {
console.log(this.photoSpotsValue)

// 地図の初期化
this.map = L.map(this.containerTarget).setView([35.474, 133.050], 13)
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(this.map)

// フォトスポットのマーカー
this.photoSpotsValue.forEach(photo_spot => {
if (photo_spot.latitude && photo_spot.longitude) {
const marker = L.marker([photo_spot.latitude, photo_spot.longitude])
.addTo(this.map)
.bindPopup(photo_spot.name)

// マーカークリック時に対応カードをハイライト
marker.on("click", () => {
this.highlight(null, photo_spot.id)
})
}
})

// イベントリスナーを登録
this.map.on("locationfound", this._onLocationFound.bind(this))
this.map.on("locationerror", this._onLocationError.bind(this))

// 初回ロード時にも現在地を取得
this.locate()
}

locate() {
if (navigator.geolocation) {
this.map.locate({ setView: true, maxZoom: 16 })
} else {
alert("お使いのブラウザは現在地の取得に対応していません。")
}
}

_onLocationFound(e) {
const redIcon = new L.Icon({
iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png',
shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
})

L.marker(e.latlng, { icon: redIcon })
.addTo(this.map)
.bindPopup("現在地")
.openPopup()
}

_onLocationError(e) {
alert("現在地を取得できませんでした: " + e.message)
}

highlight(event, spotId = null) {
// イベントから spotId を取得
const targetSpotId = spotId || event?.currentTarget.dataset.spotId
console.log("ハイライト対象ID:", targetSpotId)

// 既存ハイライトを削除
document.querySelectorAll("[data-spot-id]").forEach(el => {
el.classList.remove("ring-2", "ring-blue-500", "bg-blue-50", "animate-pulse")
})

// 対象カードを取得
const card = document.querySelector(`[data-spot-id='${targetSpotId}']`)
console.log("見つかったカード:", card)

if (card) {
card.classList.add("ring-2", "ring-blue-500", "bg-blue-50", "animate-pulse")
card.scrollIntoView({ behavior: "smooth", block: "center" })
setTimeout(() => card.classList.remove("animate-pulse"), 2000)
}
}


disconnect() {
if (this.map) {
this.map.off("locationfound")
this.map.off("locationerror")
this.map.remove()
this.map = null
}
}
}
103 changes: 0 additions & 103 deletions app/javascript/controllers/map_controller.js

This file was deleted.

Loading
Loading