# 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, Mircosoft 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));"></input> <div class="anim-buttons"> <button title="Decrease speed" onclick="anim{id}.slower()"> <i class="fa fa-minus"></i></button> <button title="First frame" onclick="anim{id}.first_frame()"> <i class="fa fa-fast-backward"></i></button> <button title="Previous frame" onclick="anim{id}.previous_frame()"> <i class="fa fa-step-backward"></i></button> <button title="Play backwards" onclick="anim{id}.reverse_animation()"> <i class="fa fa-play fa-flip-horizontal"></i></button> <button title="Pause" onclick="anim{id}.pause_animation()"> <i class="fa fa-pause"></i></button> <button title="Play" onclick="anim{id}.play_animation()"> <i class="fa fa-play"></i></button> <button title="Next frame" onclick="anim{id}.next_frame()"> <i class="fa fa-step-forward"></i></button> <button title="Last frame" onclick="anim{id}.last_frame()"> <i class="fa fa-fast-forward"></i></button> <button title="Increase speed" onclick="anim{id}.faster()"> <i class="fa fa-plus"></i></button> </div> <form title="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> """ INCLUDED_FRAMES = """ for (var i=0; i<{Nframes}; i++){{ frames[i] = "{frame_dir}/frame" + ("0000000" + i).slice(-7) + ".{frame_format}"; }} """