Index: experimental/docs/svgBackend.js |
diff --git a/experimental/docs/svgBackend.js b/experimental/docs/svgBackend.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b5907f03404944a382f7bf8d6f52b561eb48a4cb |
--- /dev/null |
+++ b/experimental/docs/svgBackend.js |
@@ -0,0 +1,246 @@ |
+var svgCache; |
+var svgDefs; |
+var svgGradients; |
+var svgNS = "http://www.w3.org/2000/svg"; |
+var svgRoot; |
+ |
+function displaySvg(displayList) { |
+ for (var index = 0; index < displayList.length; ++index) { |
+ drawToSvg(displayList[index]); |
+ } |
+} |
+ |
+function drawToSvg(display) { |
+ assert('string' == typeof(display.ref)); |
+ var cache; |
+ if (display.ref in svgCache) { |
+ cache = svgCache[display.ref]; |
+ if (display.drawDirty) { |
+ switch (cache.spec) { |
+ case "paths": |
+ svgSetPathData(cache.element, display.draw); |
+ break; |
+ case "pictures": |
+ svgSetPictureData(cache.element, display.draw); |
+ break; |
+ case "text": |
+ svgCreateText(cache.element, display.draw); |
+ break; |
+ default: |
+ assert(0); |
+ } |
+ } |
+ } else { |
+ cache = {}; |
+ cache.action = display; |
+ cache.spec = display.drawSpec; |
+ var dot = cache.spec.indexOf("."); |
+ if (dot > 0) { |
+ cache.spec = cache.spec.substring(0, dot); |
+ } |
+ switch (cache.spec) { |
+ case "paths": |
+ cache.element = svgCreatePath(display.ref, display.draw); |
+ break; |
+ case "pictures": |
+ cache.element = svgCreatePicture(display.ref, display.draw); |
+ break; |
+ case "text": |
+ cache.element = svgCreateText(display.ref, display.draw); |
+ break; |
+ default: |
+ assert(0); |
+ } |
+ } |
+ display.drawDirty = false; |
+ if (display.paintDirty) { |
+ svgSetPaintData(cache.element, display.paint); |
+ var opacity = svg_opacity(display.paint.color); |
+ cache.element.setAttribute("fill-opacity", opacity); |
+ cache.element.setAttribute("stroke-opacity", opacity); |
+ display.paintDirty = false; |
+ } |
+ assert('object' == typeof(cache)); |
+ if (!(display.ref in svgCache)) { |
+ svgRoot.appendChild(cache.element); |
+ svgCache[display.ref] = cache; |
+ } |
+} |
+ |
+function setupSvg() { |
+ svgCache = { "paths":{}, "pictures":{}, "text":{} }; |
+ svgDefs = document.createElementNS(svgNS, "defs"); |
+ svgGradients = {}; |
+ svgRoot = document.getElementById("svg"); |
+ while (svgRoot.lastChild) { |
+ svgRoot.removeChild(svgRoot.lastChild); |
+ } |
+ svgRoot.appendChild(svgDefs); |
+} |
+ |
+function svg_rbg(color) { |
+ return "rgb(" + ((color >> 16) & 0xFF) |
+ + "," + ((color >> 8) & 0xFF) |
+ + "," + ((color >> 0) & 0xFF) + ")"; |
+} |
+ |
+function svg_opacity(color) { |
+ return ((color >> 24) & 0xFF) / 255.0; |
+} |
+ |
+function svgCreatePath(key, path) { |
+ var svgPath = document.createElementNS(svgNS, "path"); |
+ svgPath.setAttribute("id", key); |
+ svgSetPathData(svgPath, path); |
+ return svgPath; |
+} |
+ |
+function svgCreatePicture(key, picture) { |
+ var svgPicture = document.createElementNS(svgNS, "g"); |
+ svgPicture.setAttribute("id", key); |
+ svgSetPictureData(svgPicture, picture); |
+ return svgPicture; |
+} |
+ |
+function svgCreateRadialGradient(key) { |
+ var g = gradients[key]; |
+ var e = document.createElementNS(svgNS, "radialGradient"); |
+ e.setAttribute("id", key); |
+ e.setAttribute("cx", g.cx); |
+ e.setAttribute("cy", g.cy); |
+ e.setAttribute("r", g.r); |
+ e.setAttribute("gradientUnits", "userSpaceOnUse"); |
+ var stopLen = g.stops.length; |
+ for (var index = 0; index < stopLen; ++index) { |
+ var stop = g.stops[index]; |
+ var color = svg_rbg(stop.color); |
+ var s = document.createElementNS(svgNS, 'stop'); |
+ s.setAttribute("offset", stop.offset); |
+ var style = "stop-color:" + svg_rbg(stop.color) + "; stop-opacity:" |
+ + svg_opacity(stop.color); |
+ s.setAttribute("style", style); |
+ e.appendChild(s); |
+ } |
+ svgGradients[key] = e; |
+ svgDefs.appendChild(e); |
+} |
+ |
+function svgCreateText(key, text) { |
+ var svgText = document.createElementNS(svgNS, "text"); |
+ svgText.setAttribute("id", key); |
+ var textNode = document.createTextNode(text.string); |
+ svgText.appendChild(textNode); |
+ svgSetTextData(svgText, text); |
+ return svgText; |
+} |
+ |
+function svgSetPathData(svgPath, path) { |
+ var dString = ""; |
+ for (var cIndex = 0; cIndex < path.length; ++cIndex) { |
+ var curveKey = Object.keys(path[cIndex])[0]; |
+ var v = path[cIndex][curveKey]; |
+ switch (curveKey) { |
+ case 'arcTo': |
+ var clockwise = 1; // to do; work in general case |
+ dString += " A" + v[4] + "," + v[4] + " 0 0," + clockwise + " " |
+ + v[2] + "," + v[3]; |
+ break; |
+ case 'close': |
+ dString += " z"; |
+ break; |
+ case 'cubic': |
+ dString += " M" + v[0] + "," + v[1]; |
+ dString += " C" + v[2] + "," + v[3] |
+ + " " + v[4] + "," + v[5] |
+ + " " + v[6] + "," + v[7]; |
+ break; |
+ case 'line': |
+ dString += " M" + v[0] + "," + v[1]; |
+ dString += " L" + v[2] + "," + v[3]; |
+ break; |
+ case 'quad': |
+ dString += " M" + v[0] + "," + v[1]; |
+ dString += " Q" + v[2] + "," + v[3] |
+ + " " + v[4] + "," + v[5]; |
+ break; |
+ default: |
+ assert(0); |
+ } |
+ } |
+ svgPath.setAttribute("d", dString); |
+} |
+ |
+function svgSetPaintData(svgElement, paint) { |
+ var color; |
+ var inPicture = 'string' == typeof(paint); |
+ if (inPicture) { |
+ paint = (new Function("return " + paint))(); |
+ assert('object' == typeof(paint) && !isArray(paint)); |
+ } |
+ if ('gradient' in paint) { |
+ var gradient = paint.gradient.split('.'); |
+ var gradName = gradient[1]; |
+ if (!svgGradients[gradName]) { |
+ svgCreateRadialGradient(gradName); |
+ } |
+ color = "url(#" + gradName + ")"; |
+ } else { |
+ color = svg_rbg(paint.color); |
+ } |
+ svgElement.setAttribute("fill", 'fill' == paint.style ? color : "none"); |
+ if ('stroke' == paint.style) { |
+ svgElement.setAttribute("stroke", color); |
+ } |
+ if ('strokeWidth' in paint) { |
+ svgElement.setAttribute("stroke-width", paint.strokeWidth); |
+ } |
+ if ('typeface' in paint) { |
+ var typeface = typefaces[paint.typeface]; |
+ var font = typeface.style; |
+ if ('textSize' in paint) { |
+ svgElement.setAttribute("font-size", paint.textSize); |
+ } |
+ if ('family' in typeface) { |
+ svgElement.setAttribute("font-family", typeface.family); |
+ } |
+ if ('textAlign' in paint) { |
+ svgElement.setAttribute("text-anchor", paint.textAlign == "right" ? "end" : assert(0)); |
+ } |
+ if ('textBaseline' in paint) { |
+ svgElement.setAttribute("alignment-baseline", paint.textBaseline); |
+ } |
+ } |
+} |
+ |
+function svgSetPictureData(svgPicture, picture) { |
+ while (svgPicture.lastChild) { |
+ svgPicture.removeChild(svgPicture.lastChild); |
+ } |
+ for (var index = 0; index < picture.length; ++index) { |
+ var entry = picture[index]; |
+ var drawObj = (new Function("return " + entry.draw))(); |
+ var drawSpec = entry.draw.split('.'); |
+ var svgElement; |
+ switch (drawSpec[0]) { |
+ case 'paths': |
+ svgElement = svgCreatePath(drawSpec[1], drawObj); |
+ break; |
+ case 'pictures': |
+ svgElement = svgCreatePicture(drawSpec[1], drawObj); |
+ break; |
+ case 'text': |
+ svgElement = svgCreateText(drawSpec[1], drawObj); |
+ break; |
+ default: |
+ assert(0); |
+ } |
+ var paintObj = (new Function("return " + entry.paint))(); |
+ svgSetPaintData(svgElement, paintObj); |
+ svgPicture.appendChild(svgElement); |
+ } |
+} |
+ |
+function svgSetTextData(svgElement, text) { |
+ svgElement.setAttribute('x', text.x); |
+ svgElement.setAttribute('y', text.y); |
+} |