1var svgCache; 2var svgDefs; 3var svgGradients; 4var svgNS = "http://www.w3.org/2000/svg"; 5var svgRoot; 6 7function displaySvg(displayList) { 8 for (var index = 0; index < displayList.length; ++index) { 9 drawToSvg(displayList[index]); 10 } 11} 12 13function drawToSvg(display) { 14 assert('string' == typeof(display.ref)); 15 var cache; 16 if (display.ref in svgCache) { 17 cache = svgCache[display.ref]; 18 if (display.drawDirty) { 19 switch (cache.spec) { 20 case "paths": 21 svgSetPathData(cache.element, display.draw); 22 break; 23 case "pictures": 24 svgSetPictureData(cache.element, display.draw); 25 break; 26 case "text": 27 svgCreateText(cache.element, display.draw); 28 break; 29 default: 30 assert(0); 31 } 32 } 33 } else { 34 cache = {}; 35 cache.action = display; 36 cache.spec = display.drawSpec; 37 var dot = cache.spec.indexOf("."); 38 if (dot > 0) { 39 cache.spec = cache.spec.substring(0, dot); 40 } 41 switch (cache.spec) { 42 case "paths": 43 cache.element = svgCreatePath(display.ref, display.draw); 44 break; 45 case "pictures": 46 cache.element = svgCreatePicture(display.ref, display.draw); 47 break; 48 case "text": 49 cache.element = svgCreateText(display.ref, display.draw); 50 break; 51 default: 52 assert(0); 53 } 54 } 55 display.drawDirty = false; 56 if (display.paintDirty) { 57 svgSetPaintData(cache.element, display.paint); 58 var opacity = svg_opacity(display.paint.color); 59 cache.element.setAttribute("fill-opacity", opacity); 60 cache.element.setAttribute("stroke-opacity", opacity); 61 display.paintDirty = false; 62 } 63 assert('object' == typeof(cache)); 64 if (!(display.ref in svgCache)) { 65 svgRoot.appendChild(cache.element); 66 svgCache[display.ref] = cache; 67 } 68} 69 70function setupSvg() { 71 svgCache = { "paths":{}, "pictures":{}, "text":{} }; 72 svgDefs = document.createElementNS(svgNS, "defs"); 73 svgGradients = {}; 74 svgRoot = document.getElementById("svg"); 75 while (svgRoot.lastChild) { 76 svgRoot.removeChild(svgRoot.lastChild); 77 } 78 svgRoot.appendChild(svgDefs); 79} 80 81function svg_rbg(color) { 82 return "rgb(" + ((color >> 16) & 0xFF) 83 + "," + ((color >> 8) & 0xFF) 84 + "," + ((color >> 0) & 0xFF) + ")"; 85} 86 87function svg_opacity(color) { 88 return ((color >> 24) & 0xFF) / 255.0; 89} 90 91function svgCreatePath(key, path) { 92 var svgPath = document.createElementNS(svgNS, "path"); 93 svgPath.setAttribute("id", key); 94 svgSetPathData(svgPath, path); 95 return svgPath; 96} 97 98function svgCreatePicture(key, picture) { 99 var svgPicture = document.createElementNS(svgNS, "g"); 100 svgPicture.setAttribute("id", key); 101 svgSetPictureData(svgPicture, picture); 102 return svgPicture; 103} 104 105function svgCreateRadialGradient(key) { 106 var g = gradients[key]; 107 var e = document.createElementNS(svgNS, "radialGradient"); 108 e.setAttribute("id", key); 109 e.setAttribute("cx", g.cx); 110 e.setAttribute("cy", g.cy); 111 e.setAttribute("r", g.r); 112 e.setAttribute("gradientUnits", "userSpaceOnUse"); 113 var stopLen = g.stops.length; 114 for (var index = 0; index < stopLen; ++index) { 115 var stop = g.stops[index]; 116 var color = svg_rbg(stop.color); 117 var s = document.createElementNS(svgNS, 'stop'); 118 s.setAttribute("offset", stop.offset); 119 var style = "stop-color:" + svg_rbg(stop.color) + "; stop-opacity:" 120 + svg_opacity(stop.color); 121 s.setAttribute("style", style); 122 e.appendChild(s); 123 } 124 svgGradients[key] = e; 125 svgDefs.appendChild(e); 126} 127 128function svgCreateText(key, text) { 129 var svgText = document.createElementNS(svgNS, "text"); 130 svgText.setAttribute("id", key); 131 var textNode = document.createTextNode(text.string); 132 svgText.appendChild(textNode); 133 svgSetTextData(svgText, text); 134 return svgText; 135} 136 137function svgSetPathData(svgPath, path) { 138 var dString = ""; 139 for (var cIndex = 0; cIndex < path.length; ++cIndex) { 140 var curveKey = Object.keys(path[cIndex])[0]; 141 var v = path[cIndex][curveKey]; 142 switch (curveKey) { 143 case 'arcTo': 144 var clockwise = 1; // to do; work in general case 145 dString += " A" + v[4] + "," + v[4] + " 0 0," + clockwise + " " 146 + v[2] + "," + v[3]; 147 break; 148 case 'close': 149 dString += " z"; 150 break; 151 case 'cubic': 152 dString += " M" + v[0] + "," + v[1]; 153 dString += " C" + v[2] + "," + v[3] 154 + " " + v[4] + "," + v[5] 155 + " " + v[6] + "," + v[7]; 156 break; 157 case 'line': 158 dString += " M" + v[0] + "," + v[1]; 159 dString += " L" + v[2] + "," + v[3]; 160 break; 161 case 'quad': 162 dString += " M" + v[0] + "," + v[1]; 163 dString += " Q" + v[2] + "," + v[3] 164 + " " + v[4] + "," + v[5]; 165 break; 166 default: 167 assert(0); 168 } 169 } 170 svgPath.setAttribute("d", dString); 171} 172 173function svgSetPaintData(svgElement, paint) { 174 var color; 175 var inPicture = 'string' == typeof(paint); 176 if (inPicture) { 177 paint = (new Function("return " + paint))(); 178 assert('object' == typeof(paint) && !isArray(paint)); 179 } 180 if ('gradient' in paint) { 181 var gradient = paint.gradient.split('.'); 182 var gradName = gradient[1]; 183 if (!svgGradients[gradName]) { 184 svgCreateRadialGradient(gradName); 185 } 186 color = "url(#" + gradName + ")"; 187 } else { 188 color = svg_rbg(paint.color); 189 } 190 svgElement.setAttribute("fill", 'fill' == paint.style ? color : "none"); 191 if ('stroke' == paint.style) { 192 svgElement.setAttribute("stroke", color); 193 } 194 if ('strokeWidth' in paint) { 195 svgElement.setAttribute("stroke-width", paint.strokeWidth); 196 } 197 if ('typeface' in paint) { 198 var typeface = typefaces[paint.typeface]; 199 var font = typeface.style; 200 if ('textSize' in paint) { 201 svgElement.setAttribute("font-size", paint.textSize); 202 } 203 if ('family' in typeface) { 204 svgElement.setAttribute("font-family", typeface.family); 205 } 206 if ('textAlign' in paint) { 207 svgElement.setAttribute("text-anchor", paint.textAlign == "right" ? "end" : assert(0)); 208 } 209 if ('textBaseline' in paint) { 210 svgElement.setAttribute("alignment-baseline", paint.textBaseline); 211 } 212 } 213} 214 215function svgSetPictureData(svgPicture, picture) { 216 while (svgPicture.lastChild) { 217 svgPicture.removeChild(svgPicture.lastChild); 218 } 219 for (var index = 0; index < picture.length; ++index) { 220 var entry = picture[index]; 221 var drawObj = (new Function("return " + entry.draw))(); 222 var drawSpec = entry.draw.split('.'); 223 var svgElement; 224 switch (drawSpec[0]) { 225 case 'paths': 226 svgElement = svgCreatePath(drawSpec[1], drawObj); 227 break; 228 case 'pictures': 229 svgElement = svgCreatePicture(drawSpec[1], drawObj); 230 break; 231 case 'text': 232 svgElement = svgCreateText(drawSpec[1], drawObj); 233 break; 234 default: 235 assert(0); 236 } 237 var paintObj = (new Function("return " + entry.paint))(); 238 svgSetPaintData(svgElement, paintObj); 239 svgPicture.appendChild(svgElement); 240 } 241} 242 243function svgSetTextData(svgElement, text) { 244 svgElement.setAttribute('x', text.x); 245 svgElement.setAttribute('y', text.y); 246} 247