263 lines
7.8 KiB
Python
263 lines
7.8 KiB
Python
|
# JavaScript template for HTMLWriter
|
||
|
JS_INCLUDE = """
|
||
|
<link rel="stylesheet"
|
||
|
href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
|
||
|
<script language="javascript">
|
||
|
function isInternetExplorer() {
|
||
|
ua = navigator.userAgent;
|
||
|
/* MSIE used to detect old browsers and Trident used to newer ones*/
|
||
|
return ua.indexOf("MSIE ") > -1 || ua.indexOf("Trident/") > -1;
|
||
|
}
|
||
|
|
||
|
/* Define the Animation class */
|
||
|
function Animation(frames, img_id, slider_id, interval, loop_select_id){
|
||
|
this.img_id = img_id;
|
||
|
this.slider_id = slider_id;
|
||
|
this.loop_select_id = loop_select_id;
|
||
|
this.interval = interval;
|
||
|
this.current_frame = 0;
|
||
|
this.direction = 0;
|
||
|
this.timer = null;
|
||
|
this.frames = new Array(frames.length);
|
||
|
|
||
|
for (var i=0; i<frames.length; i++)
|
||
|
{
|
||
|
this.frames[i] = new Image();
|
||
|
this.frames[i].src = frames[i];
|
||
|
}
|
||
|
var slider = document.getElementById(this.slider_id);
|
||
|
slider.max = this.frames.length - 1;
|
||
|
if (isInternetExplorer()) {
|
||
|
// switch from oninput to onchange because IE <= 11 does not conform
|
||
|
// with W3C specification. It ignores oninput and onchange behaves
|
||
|
// like oninput. In contrast, Microsoft Edge behaves correctly.
|
||
|
slider.setAttribute('onchange', slider.getAttribute('oninput'));
|
||
|
slider.setAttribute('oninput', null);
|
||
|
}
|
||
|
this.set_frame(this.current_frame);
|
||
|
}
|
||
|
|
||
|
Animation.prototype.get_loop_state = function(){
|
||
|
var button_group = document[this.loop_select_id].state;
|
||
|
for (var i = 0; i < button_group.length; i++) {
|
||
|
var button = button_group[i];
|
||
|
if (button.checked) {
|
||
|
return button.value;
|
||
|
}
|
||
|
}
|
||
|
return undefined;
|
||
|
}
|
||
|
|
||
|
Animation.prototype.set_frame = function(frame){
|
||
|
this.current_frame = frame;
|
||
|
document.getElementById(this.img_id).src =
|
||
|
this.frames[this.current_frame].src;
|
||
|
document.getElementById(this.slider_id).value = this.current_frame;
|
||
|
}
|
||
|
|
||
|
Animation.prototype.next_frame = function()
|
||
|
{
|
||
|
this.set_frame(Math.min(this.frames.length - 1, this.current_frame + 1));
|
||
|
}
|
||
|
|
||
|
Animation.prototype.previous_frame = function()
|
||
|
{
|
||
|
this.set_frame(Math.max(0, this.current_frame - 1));
|
||
|
}
|
||
|
|
||
|
Animation.prototype.first_frame = function()
|
||
|
{
|
||
|
this.set_frame(0);
|
||
|
}
|
||
|
|
||
|
Animation.prototype.last_frame = function()
|
||
|
{
|
||
|
this.set_frame(this.frames.length - 1);
|
||
|
}
|
||
|
|
||
|
Animation.prototype.slower = function()
|
||
|
{
|
||
|
this.interval /= 0.7;
|
||
|
if(this.direction > 0){this.play_animation();}
|
||
|
else if(this.direction < 0){this.reverse_animation();}
|
||
|
}
|
||
|
|
||
|
Animation.prototype.faster = function()
|
||
|
{
|
||
|
this.interval *= 0.7;
|
||
|
if(this.direction > 0){this.play_animation();}
|
||
|
else if(this.direction < 0){this.reverse_animation();}
|
||
|
}
|
||
|
|
||
|
Animation.prototype.anim_step_forward = function()
|
||
|
{
|
||
|
this.current_frame += 1;
|
||
|
if(this.current_frame < this.frames.length){
|
||
|
this.set_frame(this.current_frame);
|
||
|
}else{
|
||
|
var loop_state = this.get_loop_state();
|
||
|
if(loop_state == "loop"){
|
||
|
this.first_frame();
|
||
|
}else if(loop_state == "reflect"){
|
||
|
this.last_frame();
|
||
|
this.reverse_animation();
|
||
|
}else{
|
||
|
this.pause_animation();
|
||
|
this.last_frame();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Animation.prototype.anim_step_reverse = function()
|
||
|
{
|
||
|
this.current_frame -= 1;
|
||
|
if(this.current_frame >= 0){
|
||
|
this.set_frame(this.current_frame);
|
||
|
}else{
|
||
|
var loop_state = this.get_loop_state();
|
||
|
if(loop_state == "loop"){
|
||
|
this.last_frame();
|
||
|
}else if(loop_state == "reflect"){
|
||
|
this.first_frame();
|
||
|
this.play_animation();
|
||
|
}else{
|
||
|
this.pause_animation();
|
||
|
this.first_frame();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Animation.prototype.pause_animation = function()
|
||
|
{
|
||
|
this.direction = 0;
|
||
|
if (this.timer){
|
||
|
clearInterval(this.timer);
|
||
|
this.timer = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Animation.prototype.play_animation = function()
|
||
|
{
|
||
|
this.pause_animation();
|
||
|
this.direction = 1;
|
||
|
var t = this;
|
||
|
if (!this.timer) this.timer = setInterval(function() {
|
||
|
t.anim_step_forward();
|
||
|
}, this.interval);
|
||
|
}
|
||
|
|
||
|
Animation.prototype.reverse_animation = function()
|
||
|
{
|
||
|
this.pause_animation();
|
||
|
this.direction = -1;
|
||
|
var t = this;
|
||
|
if (!this.timer) this.timer = setInterval(function() {
|
||
|
t.anim_step_reverse();
|
||
|
}, this.interval);
|
||
|
}
|
||
|
</script>
|
||
|
"""
|
||
|
|
||
|
|
||
|
# Style definitions for the HTML template
|
||
|
STYLE_INCLUDE = """
|
||
|
<style>
|
||
|
.animation {
|
||
|
display: inline-block;
|
||
|
text-align: center;
|
||
|
}
|
||
|
input[type=range].anim-slider {
|
||
|
width: 374px;
|
||
|
margin-left: auto;
|
||
|
margin-right: auto;
|
||
|
}
|
||
|
.anim-buttons {
|
||
|
margin: 8px 0px;
|
||
|
}
|
||
|
.anim-buttons button {
|
||
|
padding: 0;
|
||
|
width: 36px;
|
||
|
}
|
||
|
.anim-state label {
|
||
|
margin-right: 8px;
|
||
|
}
|
||
|
.anim-state input {
|
||
|
margin: 0;
|
||
|
vertical-align: middle;
|
||
|
}
|
||
|
</style>
|
||
|
"""
|
||
|
|
||
|
|
||
|
# HTML template for HTMLWriter
|
||
|
DISPLAY_TEMPLATE = """
|
||
|
<div class="animation">
|
||
|
<img id="_anim_img{id}">
|
||
|
<div class="anim-controls">
|
||
|
<input id="_anim_slider{id}" type="range" class="anim-slider"
|
||
|
name="points" min="0" max="1" step="1" value="0"
|
||
|
oninput="anim{id}.set_frame(parseInt(this.value));">
|
||
|
<div class="anim-buttons">
|
||
|
<button title="Decrease speed" aria-label="Decrease speed" onclick="anim{id}.slower()">
|
||
|
<i class="fa fa-minus"></i></button>
|
||
|
<button title="First frame" aria-label="First frame" onclick="anim{id}.first_frame()">
|
||
|
<i class="fa fa-fast-backward"></i></button>
|
||
|
<button title="Previous frame" aria-label="Previous frame" onclick="anim{id}.previous_frame()">
|
||
|
<i class="fa fa-step-backward"></i></button>
|
||
|
<button title="Play backwards" aria-label="Play backwards" onclick="anim{id}.reverse_animation()">
|
||
|
<i class="fa fa-play fa-flip-horizontal"></i></button>
|
||
|
<button title="Pause" aria-label="Pause" onclick="anim{id}.pause_animation()">
|
||
|
<i class="fa fa-pause"></i></button>
|
||
|
<button title="Play" aria-label="Play" onclick="anim{id}.play_animation()">
|
||
|
<i class="fa fa-play"></i></button>
|
||
|
<button title="Next frame" aria-label="Next frame" onclick="anim{id}.next_frame()">
|
||
|
<i class="fa fa-step-forward"></i></button>
|
||
|
<button title="Last frame" aria-label="Last frame" onclick="anim{id}.last_frame()">
|
||
|
<i class="fa fa-fast-forward"></i></button>
|
||
|
<button title="Increase speed" aria-label="Increase speed" onclick="anim{id}.faster()">
|
||
|
<i class="fa fa-plus"></i></button>
|
||
|
</div>
|
||
|
<form title="Repetition mode" aria-label="Repetition mode" action="#n" name="_anim_loop_select{id}"
|
||
|
class="anim-state">
|
||
|
<input type="radio" name="state" value="once" id="_anim_radio1_{id}"
|
||
|
{once_checked}>
|
||
|
<label for="_anim_radio1_{id}">Once</label>
|
||
|
<input type="radio" name="state" value="loop" id="_anim_radio2_{id}"
|
||
|
{loop_checked}>
|
||
|
<label for="_anim_radio2_{id}">Loop</label>
|
||
|
<input type="radio" name="state" value="reflect" id="_anim_radio3_{id}"
|
||
|
{reflect_checked}>
|
||
|
<label for="_anim_radio3_{id}">Reflect</label>
|
||
|
</form>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
<script language="javascript">
|
||
|
/* Instantiate the Animation class. */
|
||
|
/* The IDs given should match those used in the template above. */
|
||
|
(function() {{
|
||
|
var img_id = "_anim_img{id}";
|
||
|
var slider_id = "_anim_slider{id}";
|
||
|
var loop_select_id = "_anim_loop_select{id}";
|
||
|
var frames = new Array({Nframes});
|
||
|
{fill_frames}
|
||
|
|
||
|
/* set a timeout to make sure all the above elements are created before
|
||
|
the object is initialized. */
|
||
|
setTimeout(function() {{
|
||
|
anim{id} = new Animation(frames, img_id, slider_id, {interval},
|
||
|
loop_select_id);
|
||
|
}}, 0);
|
||
|
}})()
|
||
|
</script>
|
||
|
""" # noqa: E501
|
||
|
|
||
|
|
||
|
INCLUDED_FRAMES = """
|
||
|
for (var i=0; i<{Nframes}; i++){{
|
||
|
frames[i] = "{frame_dir}/frame" + ("0000000" + i).slice(-7) +
|
||
|
".{frame_format}";
|
||
|
}}
|
||
|
"""
|