-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathbase.html
286 lines (266 loc) · 8.04 KB
/
base.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
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
{% extends 'layout0.html' %}
{% block title %}
查看比赛记录:
{% if match %}
{{match.code1.name}} vs. {{match.code2.name}} - {{record_id}}
{% elif is_local_record %}
本地记录可视化
{% else %}
课堂记录复盘
{% endif %}
{% endblock %}
{% block css %}
<style>
.screen-pool {
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.5);
margin: 15px;
}
.xscroll {
width: 100%
}
</style>
{% endblock %}
{% block content %}
{% if is_local_record %}
<style>
#upload_mask {
z-index: 900;
position: absolute;
left: 0;
right: 0;
top: 56px;
bottom: 0;
background-color: rgba(200, 220, 250, 0.8);
display: flex;
justify-content: center;
align-items: center;
}
#upload_error {
color: red;
}
</style>
<div id='upload_mask'>
<div>
<h1>上传比赛记录</h1>
<input type="file" id='upload_input'>
<div id='upload_error'></div>
</div>
</div>
{% endif %}
{{ block.super }}
{% endblock %}
{% block header %}
<div class='col-sm-4'>
<h1>
{% if match %}
<a href='../' title='{{match.code1.name}} vs. {{match.code2.name}}'>返回比赛</a>
{% elif is_local_record %}
<a href='../../game/{{AI_type}}/'>返回介绍页</a>
<a href='./'>选择新文件</a>
{% else %}
<a href='../'>返回课堂比赛结果</a>
{% endif %}
</h1>
</div>
<div class='col-sm-4 text-center'>
{% if match %}
{% if record_id %}
<h1 class='d-inline-block'>
<a href='../{{record_id | add:"-1"}}'>
上一场
</a>
</h1>
{% endif %}
<h1 class='d-inline-block' style="margin-left:10px;margin-right:10px">
{{record_id|add:"1"}}/{{match.finished_rounds}}
</h1>
{% if not_last_record %}
<h1 class='d-inline-block'>
<a href='../{{record_id | add:"1"}}'>
下一场
</a>
</h1>
{% endif %}
{% endif %}
</div>
<div class='col-sm-4'>
<div class='float-right'>
{% block control_buttons %}
<button class='btn btn-sm btn-success' id='btn_play' onclick='play_pause()'>播放/暂停</button>
<button class='btn btn-sm btn-success' id='btn_speed' onclick='switch_speed()'>播放速度: 1x</button>
{% endblock %}
</div>
</div>
{% endblock %}
{% block body %}
{% block descriptions %}
{% endblock %}
<div class='row x_block'>
<input type="range" min='0' max='4000' step='1' value="0" id="video_scroll" class='xscroll' style='margin:10px'>
</div>
<div class='row'>
{% block display_body %}
{% endblock %}
</div>
<div id='record_receiver' style="display:none">{{record_content}}</div>
{% endblock %}
{% block script %}
<script>
// 读入数据
record_obj = document.getElementById('record_receiver').innerHTML
IS_LOCAL_RECORD = record_obj == '{{ settings.LOCAL_RECORD_FLAG }}'
if (!IS_LOCAL_RECORD)
record_obj = JSON.parse(record_obj)
// 定义全局变量
CURR_FRAME = 0 // 当前渲染帧
TOTAL_FRAMES = 500 // 帧总数
ANIMATION_HANDLE = null // 播放所用AnimationHandler
TIME = LAST_TIME = null // 播放系统计时
REAL_FRAME = null // 根据时间计算真实帧位置
IS_PLAYING = false // 是否正在播放
PLAYING_SPEED = 1 // 播放速率
PLAYING_FPS = 50 // 1倍速对应FPS
// 定位控件
var scroller = document.getElementById('video_scroll')
SCROLL_DRAGGING = false // 进度条是否处于拖动状态
// 播放事件
function anim(timestamp) { // AnimationHandler内,根据时间戳更新帧数
var old_frame = CURR_FRAME
if (TIME == null) {
TIME = LAST_TIME = timestamp
REAL_FRAME = CURR_FRAME
}
else {
TIME = timestamp
REAL_FRAME = REAL_FRAME + (TIME - LAST_TIME) * PLAYING_SPEED * PLAYING_FPS / 1000
CURR_FRAME = Math.floor(REAL_FRAME)
LAST_TIME = timestamp
}
scroller.value = CURR_FRAME
if (CURR_FRAME > TOTAL_FRAMES - 1) { // 结束后自动停止
CURR_FRAME = TOTAL_FRAMES - 1
pause()
draw_frame()
} else { // 下一轮动画帧
if (old_frame != CURR_FRAME) draw_frame()
ANIMATION_HANDLE = requestAnimationFrame(anim)
}
}
function play() {
// initialize
cancelAnimationFrame(ANIMATION_HANDLE)
REAL_FRAME = TIME = LAST_TIME = null
// run process
if (CURR_FRAME >= TOTAL_FRAMES - 1) CURR_FRAME = 0
ANIMATION_HANDLE = requestAnimationFrame(anim)
IS_PLAYING = true
}
function pause() {
cancelAnimationFrame(ANIMATION_HANDLE)
IS_PLAYING = false
}
// 按钮事件
function play_pause() {
if (IS_PLAYING) pause()
else play()
}
function switch_speed() {
PLAYING_SPEED *= 2
if (PLAYING_SPEED > 8) PLAYING_SPEED = 0.25
document.getElementById('btn_speed').innerHTML = `播放速度: ${PLAYING_SPEED}x`
}
// 进度条拖动事件
function update_scroll() {
if (SCROLL_DRAGGING) {
var new_frame = scroller.value * 1
if (new_frame == CURR_FRAME) return
CURR_FRAME = new_frame
draw_frame()
}
}
scroller.addEventListener('mousedown', () => {
pause()
SCROLL_DRAGGING = true
update_scroll()
})
scroller.addEventListener('mouseup', () => {
SCROLL_DRAGGING = false
scroller.value = CURR_FRAME
})
scroller.addEventListener('mousemove', update_scroll)
// 按键逐帧播放
window.addEventListener('keypress', e => {
switch (e.code) {
// 逐帧移动
case "BracketLeft":
if (IS_PLAYING) pause()
CURR_FRAME = Math.max(CURR_FRAME - 1, 0)
scroller.value = CURR_FRAME
draw_frame()
break
case "BracketRight":
if (IS_PLAYING) pause()
CURR_FRAME = Math.min(CURR_FRAME + 1, TOTAL_FRAMES - 1)
scroller.value = CURR_FRAME
draw_frame()
break
// 播放暂停
case "Space":
case "Enter":
case "NumpadEnter":
play_pause()
break
}
})
// 初始化事件
window.addEventListener('load', () => {
var loadFunc = () => {
init()
scroller.max = TOTAL_FRAMES - 1
draw_frame()
play_pause()
}
if (IS_LOCAL_RECORD) init_local(loadFunc)
else loadFunc()
})
// 本地读取JSON记录
function init_local(callback) {
var infile = document.getElementById('upload_input'),
errors = document.getElementById('upload_error'),
upload_mask = document.getElementById('upload_mask')
infile.addEventListener('change', () => {
errors.innerHTML = ''
var data;
if (infile.files.length == 0) {
errors.innerText = `请选择比赛记录文件`
return
}
try {
let file = infile.files[0];
let reader = new FileReader();
reader.onload = function () {
var data = reader.result
try {
record_obj = JSON.parse(data)
} catch (e) {
errors.innerText = `解析比赛记录失败: ${e}`
return
}
// 回复加载流程
upload_mask.style.display = 'none'
callback()
};
reader.readAsText(file);
} catch (e) {
errors.innerText = `读取文件失败: ${e}`
}
}, false);
}
// 通用接口
function init() {// 初始化
}
function draw_frame(index = CURR_FRAME) {// 绘制指定帧
console.log(document.title = index)
}
</script>
{% endblock %}