svg-image-util.js (6573B)
1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 // Standard values to use for <img>/<embed> height & width, if requested. 7 var HOST_NODE_HEIGHT = "20"; 8 var HOST_NODE_WIDTH = "30"; 9 10 // All the possible values of "align" 11 const ALIGN_VALS = ["none", 12 "xMinYMin", "xMinYMid", "xMinYMax", 13 "xMidYMin", "xMidYMid", "xMidYMax", 14 "xMaxYMin", "xMaxYMid", "xMaxYMax"]; 15 16 // All the possible values of "meetOrSlice" 17 const MEETORSLICE_VALS = [ "meet", "slice" ]; 18 19 /** 20 * Generates full data URI for an SVG document, with the given parameters 21 * on the SVG element. 22 * 23 * @param aViewboxArr An array of four numbers, representing the 24 * viewBox attribute, or null for no viewBox. 25 * @param aWidth The width attribute, or null for no width. 26 * @param aHeight The height attribute, or null for no height. 27 * @param aAlign The 'align' component of the 28 * preserveAspectRatio attribute, or null for none. 29 * @param aMeetOrSlice The 'meetOrSlice' component of the 30 * preserveAspectRatio attribute, or null for 31 * none. (If non-null, implies non-null value for 32 * aAlign.) 33 * @param aViewParams Parameters to use for the view element. 34 * @param aFragmentIdentifier The SVG fragment identifier. 35 */ 36 function generateSVGDataURI(aViewboxArr, aWidth, aHeight, 37 aAlign, aMeetOrSlice, 38 aViewParams, aFragmentIdentifier) { 39 // prefix 40 var datauri = "data:image/svg+xml," 41 // Begin the SVG tag 42 datauri += "%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20shape-rendering%3D%22crispEdges%22"; 43 44 // Append the custom chunk from our params 45 // If we're working with views, the align customisation is applied there instead 46 datauri += generateSVGAttrsForParams(aViewboxArr, aWidth, aHeight, 47 aViewParams ? null : aAlign, 48 aMeetOrSlice); 49 50 // Add 'font-size' just in case the client wants to use ems 51 datauri += "%20font-size%3D%22" + "10px" + "%22"; 52 53 // Put closing right bracket on SVG tag 54 datauri += "%3E"; 55 56 if (aViewParams) { 57 // Give the view the id of the fragment identifier 58 datauri += "%3Cview%20id%3D%22" + aFragmentIdentifier + "%22"; 59 60 // Append the custom chunk from our view params 61 datauri += generateSVGAttrsForParams(aViewParams.viewBox, null, null, 62 aAlign, aViewParams.meetOrSlice); 63 64 datauri += "%2F%3E"; 65 } 66 67 // Add the rest of the SVG document 68 datauri += "%3Crect%20x%3D%221%22%20y%3D%221%22%20height%3D%2218%22%20width%3D%2218%22%20stroke-width%3D%222%22%20stroke%3D%22black%22%20fill%3D%22yellow%22%2F%3E%3Ccircle%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%228%22%20style%3D%22fill%3A%20blue%22%2F%3E%3C%2Fsvg%3E"; 69 70 return datauri; 71 } 72 73 // Generates just the chunk of a data URI that's relevant to 74 // the given params. 75 function generateSVGAttrsForParams(aViewboxArr, aWidth, aHeight, 76 aAlign, aMeetOrSlice) { 77 var str = ""; 78 if (aViewboxArr) { 79 str += "%20viewBox%3D%22"; 80 for (var i in aViewboxArr) { 81 str += aViewboxArr[i]; 82 if (i != aViewboxArr.length - 1) { 83 str += "%20"; 84 } 85 } 86 str += "%22"; 87 } 88 if (aWidth) { 89 str += "%20width%3D%22" + aWidth + "%22"; 90 } 91 if (aHeight) { 92 str += "%20height%3D%22" + aHeight + "%22"; 93 } 94 if (aAlign) { 95 str += "%20preserveAspectRatio%3D%22" + aAlign; 96 if (aMeetOrSlice) { 97 str += "%20" + aMeetOrSlice; 98 } 99 str += "%22"; 100 } 101 102 return str; 103 } 104 105 // Returns a newly-generated element with the given tagname, the given URI 106 // for its |src| attribute, and the given width & height values. 107 function generateHostNode(aHostNodeTagName, aUri, 108 aHostNodeWidth, aHostNodeHeight) { 109 var elem = document.createElement(aHostNodeTagName); 110 elem.setAttribute("src", aUri); 111 112 if (aHostNodeWidth) { 113 elem.setAttribute("width", aHostNodeWidth); 114 } 115 if (aHostNodeHeight) { 116 elem.setAttribute("height", aHostNodeHeight); 117 } 118 119 return elem; 120 } 121 122 // THIS IS THE CHIEF HELPER FUNCTION TO BE CALLED BY CLIENTS 123 function appendSVGArrayWithParams(aSVGParams, aHostNodeTagName) { 124 // These are width & height vals that will be used for the *host node*. 125 // (i.e. the <img> or <embed> node -- not the <svg> node) 126 var hostNodeWidthVals = [ null, HOST_NODE_WIDTH ]; 127 var hostNodeHeightVals = [ null, HOST_NODE_HEIGHT ]; 128 129 for (var i = 0; i < hostNodeWidthVals.length; i++) { 130 var hostNodeWidth = hostNodeWidthVals[i]; 131 for (var j = 0; j < hostNodeHeightVals.length; j++) { 132 var hostNodeHeight = hostNodeHeightVals[j]; 133 appendSVGSubArrayWithParams(aSVGParams, aHostNodeTagName, 134 hostNodeWidth, hostNodeHeight); 135 } 136 } 137 } 138 139 // Helper function for above, for a fixed [host-node-width][host-node-height] 140 function appendSVGSubArrayWithParams(aSVGParams, aHostNodeTagName, 141 aHostNodeWidth, aHostNodeHeight) { 142 var rootNode = document.getElementsByTagName("body")[0]; 143 for (var k = 0; k < ALIGN_VALS.length; k++) { 144 var alignVal = ALIGN_VALS[k]; 145 if (!aSVGParams.meetOrSlice) { 146 alignVal = "none"; 147 } 148 149 // Generate the Data URI 150 var uri = generateSVGDataURI(aSVGParams.viewBox, 151 aSVGParams.width, aSVGParams.height, 152 alignVal, 153 aSVGParams.meetOrSlice, 154 aSVGParams.view, 155 aSVGParams.fragmentIdentifier); 156 157 if (aSVGParams.fragmentIdentifier) { 158 uri += "#" + aSVGParams.fragmentIdentifier; 159 } 160 161 // Generate & append the host node element 162 var hostNode = generateHostNode(aHostNodeTagName, uri, 163 aHostNodeWidth, aHostNodeHeight); 164 rootNode.appendChild(hostNode); 165 166 // Cosmetic: Add a newline when we get halfway through the ALIGN_VALS 167 // and then again when we reach the end 168 if (k + 1 == ALIGN_VALS.length / 2 || 169 k + 1 == ALIGN_VALS.length) { 170 rootNode.appendChild(document.createElement("br")); 171 } 172 } 173 }