// 座標を滑らかにする Chaikin アルゴリズム function smoothLineCoordinates(coords, iterations = 3) { if (coords.length <= 2) return coords; let current = coords; for (let it = 0; it < iterations; it++) { const smoothed = [current[0]]; for (let i = 0; i < current.length - 1; i++) { const p0 = current[i]; const p1 = current[i + 1]; const q = [0.75 * p0[0] + 0.25 * p1[0], 0.75 * p0[1] + 0.25 * p1[1]]; const r = [0.25 * p0[0] + 0.75 * p1[0], 0.25 * p0[1] + 0.75 * p1[1]]; smoothed.push(q, r); } smoothed.push(current[current.length - 1]); current = smoothed; } return current; } // 2. 外部 JSON の読み込み & MapLibre へのレイヤー登録 map.on('load', async () => { try { const response = await fetch('rail_data.json'); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); geojsonData = await response.json(); // 読み込み直後に全線区の座標を平滑化 geojsonData.features.forEach(f => { f.geometry.coordinates = smoothLineCoordinates(f.geometry.coordinates, 3); }); injectCurrentYearDensity(); map.addSource('railways', { type: 'geojson', data: geojsonData }); // 路線レイヤー(外枠・ハイライト用) map.addLayer({ id: 'rail-lines-case', type: 'line', source: 'railways', layout: { 'line-join': 'round', 'line-cap': 'round' }, paint: { 'line-color': '#ffffff', 'line-width': ['interpolate', ['linear'], ['get', 'current_density'], 0, 4, 1000, 5, 4000, 6, 20000, 8, 100000, 10 ], 'line-opacity': 0.8 } }); // 路線レイヤー(本体色) map.addLayer({ id: 'rail-lines', type: 'line', source: 'railways', layout: { 'line-join': 'round', 'line-cap': 'round' }, paint: { 'line-color': [ 'step', ['get', 'current_density'], '#991b1b', // < 1,000 1000, '#dc2626', // 1,000 - 2,000 2000, '#ea580c', // 2,000 - 4,000 4000, '#ca8a04', // 4,000 - 20,000 20000, '#16a34a', // 20,000 - 100,000 100000, '#0284c7' // >= 100,000 ], 'line-width': [ 'interpolate', ['linear'], ['get', 'current_density'], 0, 2, 1000, 3, 4000, 4, 20000, 5.5, 100000, 7.5 ], 'line-opacity': 0.95 } }); if (geojsonData.features.length > 0) { selectLine(geojsonData.features[0]); } map.on('click', 'rail-lines', (e) => { if (e.features.length > 0) { const clickedId = e.features[0].properties.id; const target = geojsonData.features.find(f => f.properties.id === clickedId); if (target) selectLine(target); } }); map.on('mouseenter', 'rail-lines', () => { map.getCanvas().style.cursor = 'pointer'; }); map.on('mouseleave', 'rail-lines', () => { map.getCanvas().style.cursor = ''; }); } catch (err) { console.error("rail_data.json の読み込みに失敗しました:", err); alert("rail_data.json の読み込みに失敗しました。ローカルサーバー経由で開いてください。"); } });