-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgraph.html
More file actions
171 lines (156 loc) · 6.58 KB
/
Copy pathgraph.html
File metadata and controls
171 lines (156 loc) · 6.58 KB
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<!DOCTYPE html><html lang="ja"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width">
</head><body>
<script type="module">
import { h1, add, link } from "https://js.sabae.cc/stdom.js";
import { CSVMap } from "https://code4fukui.github.io/csv-map/csv-map.js";
import { CSV } from "https://js.sabae.cc/CSV.js";
import { QRCode } from "https://code4fukui.github.io/qr-code/qr-code.js";
import { Day } from "https://code4fukui.github.io/day-es/Day.js";
import { getCurrentPosition } from "https://js.sabae.cc/getCurrentPosition.js";
import { Geo3x3 } from "https://geo3x3.com/Geo3x3.js";
import { sleep } from "https://js.sabae.cc/sleep.js";
class WaterLevelMap extends CSVMap {
constructor() {
super();
}
async bindPopup(d, marker) {
const sensors = this.data.filter(s => s.geo3x3 == d.geo3x3);
if (sensors.length <= 1) {
return super.bindPopup(d, marker);
}
const popup = sensors.map(s => `<div style="margin-bottom: 1em">${this.makeTable(s)}</div>`).join("");
marker.bindPopup(popup, { maxHeight: 500 });
}
async getMarker(d, ll) {
const toNumber = value => {
const n = parseFloat(value);
return Number.isFinite(n) ? n : null;
};
const waterLevel = toNumber(d['河川水位']) || 0;
const levels = [
['はん濫危険水位', 'red'],
['避難判断水位', 'orange'],
['はん濫注意水位', '#ffd700'],
['水防団待機水位', '#7ac943'],
].map(([name, color]) => ({ name, color, value: toNumber(d[name]) }));
const graphMax = Math.max(waterLevel, ...levels.map(level => level.value || 0), 1);
const levelMarkers = [];
for (const level of levels) {
if (level.value == null) {
continue;
}
const y = ll[0] + level.value / graphMax * 0.01;
const marker = L.polyline([
[y, ll[1] - 0.01],
[y, ll[1] + 0.01],
], { color: level.color, weight: 3 });
levelMarkers.push(marker);
}
const marker = L.polygon([
[ll[0] + 0.01, ll[1] - 0.01],
[ll[0], ll[1] - 0.01],
[ll[0], ll[1] + 0.01],
[ll[0] + 0.01, ll[1] + 0.01],
], { color: "gray", fillColor: "gray", stroke: false });
const samples = d.waterLevelHistory || [];
const startTime = samples[0]?.time;
const elapsedTime = samples.at(-1)?.time - startTime;
const pnt = [];
pnt.push([ll[0], ll[1] - 0.01]);
if (samples.length > 1) {
for (let i = 0; i < samples.length; i++) {
const r = samples[i].waterLevel / graphMax * 0.01;
const timeRatio = elapsedTime > 0
? (samples[i].time - startTime) / elapsedTime
: i / (samples.length - 1);
pnt.push([ll[0] + r, ll[1] - 0.01 + 0.02 * timeRatio]);
}
} else {
const r = (samples[0]?.waterLevel || 0) / graphMax * 0.01;
pnt.push([ll[0] + r, ll[1] - 0.01]);
pnt.push([ll[0] + r, ll[1] - 0.01 + 0.02]);
}
pnt.push([ll[0], ll[1] + 0.01]);
const marker2 = L.polygon(pnt, { color: "blue", fillColor: "blue" });
return L.featureGroup([marker, marker2, ...levelMarkers]);
}
}
customElements.define("waterlever-map", WaterLevelMap);
onload = async () => {
document.body.style.textAlign = "center";
h1("福井県河川水位計マップ");
const map = new WaterLevelMap();
document.body.appendChild(map);
await sleep(10);
const legend = document.createElement("div");
legend.style.margin = "0.7em";
legend.innerHTML = [
["red", "はん濫危険水位"],
["orange", "避難判断水位"],
["#ffd700", "はん濫注意水位"],
["#7ac943", "水防団待機水位"],
["blue", "河川水位の推移"],
].map(([color, label]) => `<span style="display:inline-block; margin:0 .7em .4em 0"><span style="display:inline-block; width:1.8em; border-top:3px solid ${color}; margin-right:.35em; vertical-align:middle"></span>${label}</span>`).join("");
document.body.appendChild(legend);
//const base = "https://code4fukui.github.io/waterlevel_fukui/";
const base = "./";
const sensors = CSV.toJSON(await CSV.fetch(base + "sensors.csv"));
const data = CSV.toJSON(await CSV.fetch(base + "data/" + new Day().toString() + ".csv")).reverse();
console.log(data, sensors);
const getHistory = data => {
return data.slice(0, 5).reverse().map(d => ({
waterLevel: parseFloat(d.河川水位) || 0,
time: new Date(d.日時).getTime(),
label: d.河川水位 + "m(" + d.日時.substring(d.日時.length - 5) + ")",
}));
};
sensors.forEach(s => {
const d = data.find(d => d.id == s.id);
const history = getHistory(data.filter(d => d.id == s.id));
s.河川水位 = d.河川水位;
s.水位の推移 = history.map(d => d.label).join(" → ");
s.日時 = d.日時;
Object.defineProperty(s, "waterLevelHistory", { value: history });
delete s.日付;
});
map.value = sensors;
const btn = document.createElement("button");
btn.textContent = "現在位置付近を見る(GPS等使用)";
btn.style.margin = "1em";
btn.onclick = async () => {
const pos = await getCurrentPosition();
map.map.flyTo(new L.LatLng(pos.latitude, pos.longitude), 14);
};
document.body.appendChild(btn);
add("br");
link("川の防災情報 - 国土交通省", "https://www.river.go.jp/kawabou/mb?zm=11&clat=36.07241230197147&clon=136.13433837890628&fld=0&mapType=0&viewGrpStg=0&viewRd=1&viewRW=1&viewRl=1&viewRn=1&viewPoint=1&ext=0");
link("気象庁 | 今後の雨(降水短時間予報)", "https://www.jma.go.jp/bosai/kaikotan/#zoom:9/lat:35.945771/lon:136.249695/colordepth:normal/elements:rasrf&slmcs");
link("福井県の雨雲レーダー【予想60時間】 - ウェザーニュース", "https://weathernews.jp/onebox/radar/fukui/");
add("br");
link("DATA: CC BY 福井県河川水位オープンデータ", "https://github.com/code4fukui/waterlevel_fukui");
link("水位計位置オープンデータ表示", "./");
link("src on GitHub", "https://github.com/code4fukui/waterlevel_fukui");
add("br");
document.body.appendChild(new QRCode());
// position hash
if (document.location.hash.length > 1) {
const geo3x3 = document.location.hash.substring(1);
const pos = Geo3x3.decode(geo3x3);
console.log(pos);
await sleep(100);
//map.map.setView([pos.lat, pos.lng], pos.level);
map.map.flyTo(new L.LatLng(pos.lat, pos.lng), pos.level);
}
const setHash = () => {
const ll = map.map.getCenter();
const z = map.map.getZoom();
//console.log(ll, z);
const geo3x3 = Geo3x3.encode(ll.lat, ll.lng, z);
document.location.hash = geo3x3;
};
map.map.on("moveend", setHash);
map.map.on("zoomlevelschange", setHash);
};
</script>
</body>
</html>