-
Notifications
You must be signed in to change notification settings - Fork 4
/
replay.html
125 lines (104 loc) · 3.93 KB
/
replay.html
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
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CriticalSnake Replay</title>
<link rel="stylesheet" href="3rd-party/leaflet16/leaflet.css">
<style>
body {
font-size: 1rem;
}
#osm-map {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="osm-map"></div>
<script src="3rd-party/leaflet16/leaflet.js"></script>
<script src="3rd-party/leaflet-semicircle20/Semicircle.js"></script>
<script src="3rd-party/lzstring14/lz-string.min.js"></script>
<script src="critical-snake/core.js"></script>
<script src="critical-snake/playback.js"></script>
<script src="critical-snake/playback-controls.js"></script>
<script src="critical-snake/bikemap.js"></script>
<script>
const bikeMap = createBikeMap(L);
bikeMap.playbackGroup = new L.Control.PlaybackGroup({
position: 'bottomleft',
fps: CriticalSnake.PlaybackOptions.fps,
speedup: CriticalSnake.PlaybackOptions.speedup,
autoLimitFps: CriticalSnake.PlaybackOptions.autoLimitFps,
allowDownload: false,
status: CriticalSnake.PlaybackStatus,
});
// We use the default zoom controls group, but we add the playback group
// first, so that it shows up below the zoom group.
bikeMap.playbackGroup.addTo(bikeMap);
bikeMap.loadingGroup.addTo(bikeMap);
bikeMap.browseGroup.addTo(bikeMap);
bikeMap.zoomButtons.addTo(bikeMap);
bikeMap.statsLabel.addTo(bikeMap);
bikeMap.browseGroup.show();
const playback = new CriticalSnake.Playback(bikeMap);
bikeMap.browseGroup.fileSelected = function(blob) {
// Validate selection and set visual indication for the loading progress.
bikeMap.browseGroup.hide();
bikeMap.loadingGroup.show();
bikeMap.playbackGroup.hide();
const sourceFileName = blob.name;
// Load and parse the actual file content.
const reader = new FileReader();
reader.onload = function(e) {
try {
const content = decompressReplay(e.target.result);
playback.setDataset(JSON.parse(content));
refreshView(playback.dataset.begin);
bikeMap.playbackGroup.show(playback.dataset.begin, playback.dataset.end);
bikeMap.statsLabel.show();
}
catch (ex) {
bikeMap.browseGroup.show();
console.error("JSON parsing for file", sourceFileName,
"failed with", ex);
}
bikeMap.loadingGroup.hide();
};
// Give the UI a chance to refresh and show the loading state.
setTimeout(() => reader.readAsText(blob), 10);
};
function decompressReplay(data) {
const kilobyte = (str) => Math.round((str.length * 2) / 1024);
console.log("Compressed size is:", kilobyte(data), "KB");
const decompressionBegin = Date.now();
const content = LZString.decompressFromUTF16(data);
console.log("Decompressed size is:", kilobyte(content), "KB");
console.log("Decompression took:", Date.now() - decompressionBegin, "ms");
return content;
}
function refreshView(playbackTime) {
playbackTime = playbackTime || CriticalSnake.PlaybackStatus.frameTime;
const refreshViewBegin = Date.now();
const bikeCount = playback.drawScene(playbackTime);
bikeMap.statsLabel.update(playbackTime, bikeCount);
const diff = Date.now() - refreshViewBegin;
//console.log("Rendering frame took:", Math.round(diff / 10) * 10, "ms");
}
bikeMap.playbackGroup.renderFrame = function(timestamp) {
refreshView(timestamp);
}
bikeMap.playbackGroup.playbackToggled = function(running) {
if (running) {
const fps = CriticalSnake.PlaybackOptions.fps;
const speed = CriticalSnake.PlaybackOptions.speedup;
console.log(`Replay ${fps}FPS in ${speed}x time-lapse`);
}
}
</script>
</body>
</html>