_animation_data.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. # JavaScript template for HTMLWriter
  2. JS_INCLUDE = """
  3. <link rel="stylesheet"
  4. href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
  5. <script language="javascript">
  6. function isInternetExplorer() {
  7. ua = navigator.userAgent;
  8. /* MSIE used to detect old browsers and Trident used to newer ones*/
  9. return ua.indexOf("MSIE ") > -1 || ua.indexOf("Trident/") > -1;
  10. }
  11. /* Define the Animation class */
  12. function Animation(frames, img_id, slider_id, interval, loop_select_id){
  13. this.img_id = img_id;
  14. this.slider_id = slider_id;
  15. this.loop_select_id = loop_select_id;
  16. this.interval = interval;
  17. this.current_frame = 0;
  18. this.direction = 0;
  19. this.timer = null;
  20. this.frames = new Array(frames.length);
  21. for (var i=0; i<frames.length; i++)
  22. {
  23. this.frames[i] = new Image();
  24. this.frames[i].src = frames[i];
  25. }
  26. var slider = document.getElementById(this.slider_id);
  27. slider.max = this.frames.length - 1;
  28. if (isInternetExplorer()) {
  29. // switch from oninput to onchange because IE <= 11 does not conform
  30. // with W3C specification. It ignores oninput and onchange behaves
  31. // like oninput. In contrast, Microsoft Edge behaves correctly.
  32. slider.setAttribute('onchange', slider.getAttribute('oninput'));
  33. slider.setAttribute('oninput', null);
  34. }
  35. this.set_frame(this.current_frame);
  36. }
  37. Animation.prototype.get_loop_state = function(){
  38. var button_group = document[this.loop_select_id].state;
  39. for (var i = 0; i < button_group.length; i++) {
  40. var button = button_group[i];
  41. if (button.checked) {
  42. return button.value;
  43. }
  44. }
  45. return undefined;
  46. }
  47. Animation.prototype.set_frame = function(frame){
  48. this.current_frame = frame;
  49. document.getElementById(this.img_id).src =
  50. this.frames[this.current_frame].src;
  51. document.getElementById(this.slider_id).value = this.current_frame;
  52. }
  53. Animation.prototype.next_frame = function()
  54. {
  55. this.set_frame(Math.min(this.frames.length - 1, this.current_frame + 1));
  56. }
  57. Animation.prototype.previous_frame = function()
  58. {
  59. this.set_frame(Math.max(0, this.current_frame - 1));
  60. }
  61. Animation.prototype.first_frame = function()
  62. {
  63. this.set_frame(0);
  64. }
  65. Animation.prototype.last_frame = function()
  66. {
  67. this.set_frame(this.frames.length - 1);
  68. }
  69. Animation.prototype.slower = function()
  70. {
  71. this.interval /= 0.7;
  72. if(this.direction > 0){this.play_animation();}
  73. else if(this.direction < 0){this.reverse_animation();}
  74. }
  75. Animation.prototype.faster = function()
  76. {
  77. this.interval *= 0.7;
  78. if(this.direction > 0){this.play_animation();}
  79. else if(this.direction < 0){this.reverse_animation();}
  80. }
  81. Animation.prototype.anim_step_forward = function()
  82. {
  83. this.current_frame += 1;
  84. if(this.current_frame < this.frames.length){
  85. this.set_frame(this.current_frame);
  86. }else{
  87. var loop_state = this.get_loop_state();
  88. if(loop_state == "loop"){
  89. this.first_frame();
  90. }else if(loop_state == "reflect"){
  91. this.last_frame();
  92. this.reverse_animation();
  93. }else{
  94. this.pause_animation();
  95. this.last_frame();
  96. }
  97. }
  98. }
  99. Animation.prototype.anim_step_reverse = function()
  100. {
  101. this.current_frame -= 1;
  102. if(this.current_frame >= 0){
  103. this.set_frame(this.current_frame);
  104. }else{
  105. var loop_state = this.get_loop_state();
  106. if(loop_state == "loop"){
  107. this.last_frame();
  108. }else if(loop_state == "reflect"){
  109. this.first_frame();
  110. this.play_animation();
  111. }else{
  112. this.pause_animation();
  113. this.first_frame();
  114. }
  115. }
  116. }
  117. Animation.prototype.pause_animation = function()
  118. {
  119. this.direction = 0;
  120. if (this.timer){
  121. clearInterval(this.timer);
  122. this.timer = null;
  123. }
  124. }
  125. Animation.prototype.play_animation = function()
  126. {
  127. this.pause_animation();
  128. this.direction = 1;
  129. var t = this;
  130. if (!this.timer) this.timer = setInterval(function() {
  131. t.anim_step_forward();
  132. }, this.interval);
  133. }
  134. Animation.prototype.reverse_animation = function()
  135. {
  136. this.pause_animation();
  137. this.direction = -1;
  138. var t = this;
  139. if (!this.timer) this.timer = setInterval(function() {
  140. t.anim_step_reverse();
  141. }, this.interval);
  142. }
  143. </script>
  144. """
  145. # Style definitions for the HTML template
  146. STYLE_INCLUDE = """
  147. <style>
  148. .animation {
  149. display: inline-block;
  150. text-align: center;
  151. }
  152. input[type=range].anim-slider {
  153. width: 374px;
  154. margin-left: auto;
  155. margin-right: auto;
  156. }
  157. .anim-buttons {
  158. margin: 8px 0px;
  159. }
  160. .anim-buttons button {
  161. padding: 0;
  162. width: 36px;
  163. }
  164. .anim-state label {
  165. margin-right: 8px;
  166. }
  167. .anim-state input {
  168. margin: 0;
  169. vertical-align: middle;
  170. }
  171. </style>
  172. """
  173. # HTML template for HTMLWriter
  174. DISPLAY_TEMPLATE = """
  175. <div class="animation">
  176. <img id="_anim_img{id}">
  177. <div class="anim-controls">
  178. <input id="_anim_slider{id}" type="range" class="anim-slider"
  179. name="points" min="0" max="1" step="1" value="0"
  180. oninput="anim{id}.set_frame(parseInt(this.value));">
  181. <div class="anim-buttons">
  182. <button title="Decrease speed" aria-label="Decrease speed" onclick="anim{id}.slower()">
  183. <i class="fa fa-minus"></i></button>
  184. <button title="First frame" aria-label="First frame" onclick="anim{id}.first_frame()">
  185. <i class="fa fa-fast-backward"></i></button>
  186. <button title="Previous frame" aria-label="Previous frame" onclick="anim{id}.previous_frame()">
  187. <i class="fa fa-step-backward"></i></button>
  188. <button title="Play backwards" aria-label="Play backwards" onclick="anim{id}.reverse_animation()">
  189. <i class="fa fa-play fa-flip-horizontal"></i></button>
  190. <button title="Pause" aria-label="Pause" onclick="anim{id}.pause_animation()">
  191. <i class="fa fa-pause"></i></button>
  192. <button title="Play" aria-label="Play" onclick="anim{id}.play_animation()">
  193. <i class="fa fa-play"></i></button>
  194. <button title="Next frame" aria-label="Next frame" onclick="anim{id}.next_frame()">
  195. <i class="fa fa-step-forward"></i></button>
  196. <button title="Last frame" aria-label="Last frame" onclick="anim{id}.last_frame()">
  197. <i class="fa fa-fast-forward"></i></button>
  198. <button title="Increase speed" aria-label="Increase speed" onclick="anim{id}.faster()">
  199. <i class="fa fa-plus"></i></button>
  200. </div>
  201. <form title="Repetition mode" aria-label="Repetition mode" action="#n" name="_anim_loop_select{id}"
  202. class="anim-state">
  203. <input type="radio" name="state" value="once" id="_anim_radio1_{id}"
  204. {once_checked}>
  205. <label for="_anim_radio1_{id}">Once</label>
  206. <input type="radio" name="state" value="loop" id="_anim_radio2_{id}"
  207. {loop_checked}>
  208. <label for="_anim_radio2_{id}">Loop</label>
  209. <input type="radio" name="state" value="reflect" id="_anim_radio3_{id}"
  210. {reflect_checked}>
  211. <label for="_anim_radio3_{id}">Reflect</label>
  212. </form>
  213. </div>
  214. </div>
  215. <script language="javascript">
  216. /* Instantiate the Animation class. */
  217. /* The IDs given should match those used in the template above. */
  218. (function() {{
  219. var img_id = "_anim_img{id}";
  220. var slider_id = "_anim_slider{id}";
  221. var loop_select_id = "_anim_loop_select{id}";
  222. var frames = new Array({Nframes});
  223. {fill_frames}
  224. /* set a timeout to make sure all the above elements are created before
  225. the object is initialized. */
  226. setTimeout(function() {{
  227. anim{id} = new Animation(frames, img_id, slider_id, {interval},
  228. loop_select_id);
  229. }}, 0);
  230. }})()
  231. </script>
  232. """
  233. INCLUDED_FRAMES = """
  234. for (var i=0; i<{Nframes}; i++){{
  235. frames[i] = "{frame_dir}/frame" + ("0000000" + i).slice(-7) +
  236. ".{frame_format}";
  237. }}
  238. """