1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
import parksData from "@/data/kodaira-parks.json";
import osmData from "@/data/parks-geojson";
import nearbyData from "@/data/kodaira-nearby-parks.json";
import facilitiesData from "@/data/kodaira-facilities.json";
import nearbyFacilitiesData from "@/data/kodaira-nearby-facilities.json";
export type Park = Record<string, string>;
function nearbyCentroid(feature: any): [number, number] {
const g = feature.geometry;
if (g.type === "Point") return [g.coordinates[1], g.coordinates[0]];
const ring = g.type === "Polygon" ? g.coordinates[0] : g.coordinates[0][0];
if (!ring?.length) return [0, 0];
let lat = 0;
let lon = 0;
for (const [x, y] of ring) {
lon += x;
lat += y;
}
return [lat / ring.length, lon / ring.length];
}
function mapsQueryForNearby(name: string, city: string): string {
return name ? (city && !name.includes(city) ? `${city}${name}` : name) : "";
}
// 「小平市小川町2-1325」→「小川町」。公共施設の住所から町名を取り出す。
function townFromAddress(address: string): string {
const match = /^小平市(.+?)(?:\d|$)/.exec(address || "");
return match ? match[1].trim() : "";
}
// 市境500m以内の市外公園。小平市の公園と同じ表に「市外」バッジ付きで並べる。
const nearbyRows: Park[] = ((nearbyData as any).features ?? []).map((f: any) => {
const p = f.properties || {};
const [lat, lon] = nearbyCentroid(f);
const area = Math.round(Number(p.area_m2) || 0);
const name = String(p.name || "").trim();
const mapsQuery = name
? mapsQueryForNearby(name, String(p.city || ""))
: `${lat},${lon}`;
return {
"公園名": name,
"住所": p.city ? `${p.city}(市外)` : "市外",
"町名": "市外",
"面積㎡": area ? String(area) : "",
"500㎡以上": "",
"種別": "市外",
"南西部指定管理": "",
"トイレ": "",
"水飲み場": "",
"ベンチ・椅子": "",
"テーブル": "",
"パーゴラ": "",
"東屋": "",
"防災用具": "",
"ボール遊び": "",
"遊具": "",
"駐車場": "",
"その他設備": "",
"緯度": String(lat),
"経度": String(lon),
"備考": `市外・小平市境から約${Math.round(Number(p.distance_m) || 0)}m${
f.geometry?.type === "Point" ? "・範囲未取得" : ""
}`,
"設置者": "市外",
"状態": "",
"地図キー": p.key || `${p.osm_type || ""}/${p.osm_id || ""}`,
"地図URL": `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(mapsQuery)}`,
};
});
// 市内・市外の公共施設を公園一覧と同じ行形式にする。
function facilityRow(f: any, nearby: boolean): Park {
const name = String(f.name || "").trim();
const type = String(f.type || "");
const city = String(f.city || "").trim();
const address = String(f.address || city || (nearby ? "市外" : "")).trim();
const hours = f.hours ? `開館 ${f.hours}` : "";
const closed = f.closed ? `休館 ${f.closed}` : "";
const note = [type, hours, closed, f.note].filter(Boolean).join("。");
const mapsQuery = nearby ? mapsQueryForNearby(name, city) : `小平市${name}`;
const toilet = f.toilet === "○" ? "○" : "";
const water = f.water === "○" ? "○" : "";
return {
"公園名": name,
"住所": address,
"町名": nearby ? "市外" : townFromAddress(address),
"面積㎡": "",
"500㎡以上": "",
"種別": type,
"南西部指定管理": "",
"トイレ": toilet,
"水飲み場": "",
"給水": water,
"ベンチ・椅子": "",
"テーブル": "",
"パーゴラ": "",
"東屋": "",
"防災用具": "",
"ボール遊び": "",
"遊具": "",
"駐車場": "",
"その他設備": "",
"緯度": f.lat != null ? String(f.lat) : "",
"経度": f.lon != null ? String(f.lon) : "",
"備考": note,
"設置者": nearby ? "市外" : "小平市",
"状態": "",
"地図URL": `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(mapsQuery)}`,
"公式URL": String(f.source || ""),
"施設": "1",
};
}
const facilityRows: Park[] = [
...(facilitiesData as any[]).map((f) => facilityRow(f, false)),
...(nearbyFacilitiesData as any[]).map((f) => facilityRow(f, true)),
];
export const parks: Park[] = [
...(parksData as Park[]),
...nearbyRows,
...facilityRows,
];
export const total = parks.length;
export const towns = [...new Set(parks.map((p) => p["町名"]).filter(Boolean))].sort(
(a, b) => a.localeCompare(b, "ja"),
);
// OpenStreetMapにポリゴンがあり、地図から位置を表示できる公園名。
export const mappedNames = new Set<string>([
...(osmData as any).features
.map((f: any) => f.properties?.our_name)
.filter(Boolean),
...((nearbyData as any).features ?? [])
.map((f: any) => String(f.properties?.name || "").trim())
.filter(Boolean),
]);
|