smil-grid.js (7566B)
1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ 2 /* vim: set ts=2 sw=2 sts=2 et: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* Javascript library for dynamically generating a simple SVG/SMIL reftest 8 * with several copies of the same animation, each seeked to a different time. 9 */ 10 11 // Global variables 12 const START_TIMES = [ "4.0s", "3.0s", "2.7s", 13 "2.25s", "2.01s", "1.5s", 14 "1.4s", "1.0s", "0.5s" ]; 15 16 const X_POSNS = [ "20px", "70px", "120px", 17 "20px", "70px", "120px", 18 "20px", "70px", "120px" ]; 19 20 const Y_POSNS = [ "20px", "20px", "20px", 21 "70px", "70px", "70px", 22 "120px", "120px", "120px" ]; 23 24 const DURATION = "2s"; 25 const SNAPSHOT_TIME ="3"; 26 const SVGNS = "http://www.w3.org/2000/svg"; 27 28 // Convenience wrapper using testAnimatedGrid to make 15pt-by-15pt rects 29 function testAnimatedRectGrid(animationTagName, animationAttrHashList) { 30 var targetTagName = "rect"; 31 var targetAttrHash = {"width" : "15px", 32 "height" : "15px" }; 33 testAnimatedGrid(targetTagName, targetAttrHash, 34 animationTagName, animationAttrHashList); 35 } 36 37 // Convenience wrapper using testAnimatedGrid to make grid of text 38 function testAnimatedTextGrid(animationTagName, animationAttrHashList) { 39 var targetTagName = "text"; 40 var targetAttrHash = { }; 41 testAnimatedGrid(targetTagName, targetAttrHash, 42 animationTagName, animationAttrHashList); 43 } 44 45 // Generates a visual grid of elements of type "targetTagName", with the 46 // attribute values given in targetAttrHash. Each generated element has 47 // exactly one child -- an animation element of type "animationTagName", with 48 // the attribute values given in animationAttrHash. 49 function testAnimatedGrid(targetTagName, targetAttrHash, 50 animationTagName, animationAttrHashList) { 51 // SANITY CHECK 52 const numElementsToMake = START_TIMES.length; 53 if (X_POSNS.length != numElementsToMake || 54 Y_POSNS.length != numElementsToMake) { 55 return; 56 } 57 58 for (var i = 0; i < animationAttrHashList.length; i++) { 59 var animationAttrHash = animationAttrHashList[i]; 60 // Default to fill="freeze" so we can test the final value of the animation 61 if (!animationAttrHash["fill"]) { 62 animationAttrHash["fill"] = "freeze"; 63 } 64 } 65 66 // Build the grid! 67 var svg = document.documentElement; 68 for (var i = 0; i < numElementsToMake; i++) { 69 // Build target & animation elements 70 var targetElem = buildElement(targetTagName, targetAttrHash); 71 for (var j = 0; j < animationAttrHashList.length; j++) { 72 var animationAttrHash = animationAttrHashList[j]; 73 var animElem = buildElement(animationTagName, animationAttrHash); 74 75 // Customize them using global constant values 76 targetElem.setAttribute("x", X_POSNS[i]); 77 targetElem.setAttribute("y", Y_POSNS[i]); 78 animElem.setAttribute("begin", START_TIMES[i]); 79 animElem.setAttribute("dur", DURATION); 80 81 // Append to target 82 targetElem.appendChild(animElem); 83 } 84 // Insert target into DOM 85 svg.appendChild(targetElem); 86 } 87 88 // Take snapshot 89 setTimeAndSnapshot(SNAPSHOT_TIME, true); 90 } 91 92 // Generates a visual grid of elements of type |graphicElemTagName|, with the 93 // attribute values given in |graphicElemAttrHash|. This is a variation of the 94 // above function. We use <defs> to include the reference elements because 95 // some animatable properties are only applicable to some specific elements 96 // (e.g. feFlood, stop), so then we apply an animation element of type 97 // |animationTagName|, with the attribute values given in |animationAttrHash|, 98 // to those specific elements. |defTagNameList| is an array of tag names. 99 // We will create elements hierarchically according to this array. The first tag 100 // in |defTagNameList| is the outer-most one in <defs>, and the last tag is the 101 // inner-most one and it is the target to which the animation element will be 102 // applied. We visualize the effect of our animation by referencing each 103 // animated subtree from some graphical element that we generate. The 104 // |graphicElemIdValueProperty| parameter provides the name of the CSS property 105 // that we should use to hook up this reference. 106 // 107 // e.g. if a caller passes a defTagNameList of [ "linearGradient", "stop" ], 108 // this function will generate the following subtree: 109 // <defs> 110 // <linearGradient id="elem0"> 111 // <stop> 112 // <animate ..../> 113 // </stop> 114 // </linearGradient> 115 // <linearGradient id="elem1"> 116 // <stop> 117 // <animate ..../> 118 // </stop> 119 // </linearGradient> 120 // 121 // <!--- more similar linearGradients here, up to START_TIMES.length --> 122 // </defs> 123 function testAnimatedGridWithDefs(graphicElemTagName, 124 graphicElemAttrHash, 125 graphicElemIdValuedProperty, 126 defTagNameList, 127 animationTagName, 128 animationAttrHashList) { 129 // SANITY CHECK 130 const numElementsToMake = START_TIMES.length; 131 if (X_POSNS.length != numElementsToMake || 132 Y_POSNS.length != numElementsToMake) { 133 return; 134 } 135 136 if (defTagNameList.length == 0) { 137 return; 138 } 139 140 for (var i = 0; i < animationAttrHashList.length; i++) { 141 var animationAttrHash = animationAttrHashList[i]; 142 // Default to fill="freeze" so we can test the final value of the animation 143 if (!animationAttrHash["fill"]) { 144 animationAttrHash["fill"] = "freeze"; 145 } 146 } 147 148 var svg = document.documentElement; 149 150 // Build defs element. 151 var defs = buildElement('defs'); 152 for (var i = 0; i < numElementsToMake; i++) { 153 // This will track the innermost element in our subtree: 154 var innerElement = defs; 155 156 for (var defIdx = 0; defIdx < defTagNameList.length; ++defIdx) { 157 // Set an ID on the first level of nesting (on child of defs): 158 var attrs = defIdx == 0 ? { "id": "elem" + i } : {}; 159 160 var newElem = buildElement(defTagNameList[defIdx], attrs); 161 innerElement.appendChild(newElem); 162 innerElement = newElem; 163 } 164 165 for (var j = 0; j < animationAttrHashList.length; ++j) { 166 var animationAttrHash = animationAttrHashList[j]; 167 var animElem = buildElement(animationTagName, animationAttrHash); 168 animElem.setAttribute("begin", START_TIMES[i]); 169 animElem.setAttribute("dur", DURATION); 170 innerElement.appendChild(animElem); 171 } 172 } 173 svg.appendChild(defs); 174 175 // Build the grid! 176 for (var i = 0; i < numElementsToMake; ++i) { 177 var graphicElem = buildElement(graphicElemTagName, graphicElemAttrHash); 178 graphicElem.setAttribute("x", X_POSNS[i]); 179 graphicElem.setAttribute("y", Y_POSNS[i]); 180 graphicElem.setAttribute("style", graphicElemIdValuedProperty + 181 ":url(#elem" + i + ")"); 182 svg.appendChild(graphicElem); 183 } 184 185 // Take snapshot 186 setTimeAndSnapshot(SNAPSHOT_TIME, true); 187 } 188 189 function buildElement(tagName, attrHash) { 190 var elem = document.createElementNS(SVGNS, tagName); 191 for (var attrName in attrHash) { 192 var attrValue = attrHash[attrName]; 193 elem.setAttribute(attrName, attrValue); 194 } 195 // If we're creating a text node, populate it with some text. 196 if (tagName == "text") { 197 elem.appendChild(document.createTextNode("abc")); 198 } 199 return elem; 200 }