PageSourceSearch

https://hotokami.jp/assets/services/map_initializer-ac8982e2.js

js hotokami.jp collected 2026-09-24 09:44:41 UTC 5,066 bytes, 156 lines download raw bytes

1/**
2 * マップ初期化サービス
3 * MapKitControllerからマップ初期化ロジックを分離
4 */
5export default class MapInitializer {
6	static DEFAULT_CENTER = {lat: 35.6762, lng: 139.6503}; // 東京
7
8	constructor(controller) {
9		this.controller = controller;
10	}
11
12	/**
13	 * マップを初期化
14	 * @param {Element} mapElement - マップ要素
15	 * @param {Object} options - 初期化オプション
16	 * @returns {Promise<Object>} 初期化されたマップ
17	 */
18	async initializeMap(mapElement, options = {}) {
19		await this._ensureMapkitToken();
20
21		const {
22			initialCenterLat,
23			initialCenterLng,
24			showsUserLocationControl = false,
25		} = options;
26
27		// 分割前と同じロジック: undefined や null の場合はDEFAULT_CENTERを使用
28		const lat = initialCenterLat || MapInitializer.DEFAULT_CENTER.lat;
29		const lng = initialCenterLng || MapInitializer.DEFAULT_CENTER.lng;
30
31		console.log('MapInitializer: 初期化座標', {
32			initialCenterLat,
33			initialCenterLng,
34			lat,
35			lng,
36			DEFAULT_CENTER: MapInitializer.DEFAULT_CENTER,
37		});
38
39		const center = new mapkit.Coordinate(lat, lng);
40
41		const map = new mapkit.Map(mapElement, {
42			center,
43			region: new mapkit.CoordinateRegion(center, new mapkit.CoordinateSpan(0.1, 0.1)),
44			showsMapTypeControl: true,
45			showsZoomControl: true,
46			showsCompass: mapkit.FeatureVisibility.Visible,
47			showsScale: mapkit.FeatureVisibility.Visible,
48			showsUserLocationControl,
49		});
50
51		this._addCustomControls(map, options);
52
53		return map;
54	}
55
56	/**
57	 * カスタムコントロールを追加
58	 * @private
59	 */
60	_addCustomControls(map, options) {
61		const {
62			showsSearchAtCenterButton = false,
63			showsRefreshButton = false,
64			searchAtCenterUrl = '/nearby_map/',
65		} = options;
66
67		const controls = [
68			{cond: showsSearchAtCenterButton, fn: () => this._addSearchAtCenterControl(map, searchAtCenterUrl)},
69			{cond: showsRefreshButton, fn: () => this._addRefreshControl(map)},
70		];
71		controls.forEach(({cond, fn}) => cond && fn());
72	}
73
74	/**
75	 * 中心検索コントロールを追加
76	 * @private
77	 */
78	_addSearchAtCenterControl(map, searchAtCenterUrl) {
79		const btn = document.createElement('button');
80		btn.className = 'absolute z-50 h-8 px-3 flex items-center bg-white/70 rounded-full shadow-md '
81                    + 'border-none cursor-pointer backdrop-blur-sm top-1 md:top-2 right-28 md:right-32';
82		btn.title = 'この中心で検索マップを開く';
83		btn.innerHTML = `
84      <span class="mr-2 text-xs font-medium">表示位置で再検索</span>
85      <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">
86        <path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/>
87        <path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/>
88      </svg>`;
89		btn.addEventListener('click', () => {
90			const {latitude, longitude} = map.region.center;
91			window.open(`${searchAtCenterUrl}?lat=${latitude}&lng=${longitude}`, '_blank');
92		});
93		map.element.parentNode.appendChild(btn);
94	}
95
96	/**
97	 * リフレッシュコントロールを追加
98	 * @private
99	 */
100	_addRefreshControl(map) {
101		const btn = document.createElement('button');
102		btn.className = 'absolute z-50 w-8 h-8 flex items-center justify-center bg-white/70 rounded-full shadow-md '
103                    + 'border-none cursor-pointer p-0 backdrop-blur-sm top-1 md:top-2 right-28 md:right-32';
104		btn.title = '表示範囲で再検索';
105		btn.innerHTML = `
106      <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
107        <path stroke-linecap="round" stroke-linejoin="round"
108          d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
109      </svg>`;
110		btn.addEventListener('click', () => {
111			if (this.controller.refreshSearch) {
112				this.controller.refreshSearch();
113			}
114		});
115		map.element.parentNode.appendChild(btn);
116	}
117
118	/**
119	 * MapKitトークンを確保
120	 * @private
121	 */
122	async _ensureMapkitToken() {
123		if (window.mapkitInitialized) {
124			return;
125		}
126
127		try {
128			const token = await fetch('/api/v1/mapkit/token/')
129				.then(res => {
130					if (!res.ok) {
131						throw new Error('トークンの取得に失敗しました');
132					}
133
134					return res.text();
135				})
136				.then(text => {
137					if (!text) {
138						throw new Error('MapKitトークンが空です');
139					}
140
141					try {
142						return JSON.parse(text).token;
143					} catch (e) {
144						console.error('MapKitトークンのJSONパースに失敗しました:', text);
145						throw new Error('無効なMapKitトークン形式です');
146					}
147				});
148
149			mapkit.init({authorizationCallback: done => done(token)});
150			window.mapkitInitialized = true;
151		} catch (error) {
152			console.error('MapKit初期化エラー:', error);
153			throw error;
154		}
155	}
156}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.