Home | History | Annotate | Download | only in docs
      1 var svgCache;
      2 var svgDefs;
      3 var svgGradients;
      4 var svgNS = "http://www.w3.org/2000/svg";
      5 var svgRoot;
      6 
      7 function displaySvg(displayList) {
      8     for (var index = 0; index < displayList.length; ++index) {
      9         drawToSvg(displayList[index]);
     10     }
     11 }
     12 
     13 function 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 
     70 function 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 
     81 function svg_rbg(color) {
     82     return "rgb(" + ((color >> 16) & 0xFF)
     83             + "," + ((color >>  8) & 0xFF)
     84             + "," + ((color >>  0) & 0xFF) + ")";
     85 }
     86 
     87 function svg_opacity(color) {
     88     return ((color >> 24) & 0xFF) / 255.0;
     89 }
     90 
     91 function svgCreatePath(key, path) {
     92     var svgPath = document.createElementNS(svgNS, "path");
     93     svgPath.setAttribute("id", key);
     94     svgSetPathData(svgPath, path);
     95     return svgPath;
     96 }
     97 
     98 function svgCreatePicture(key, picture) {
     99     var svgPicture = document.createElementNS(svgNS, "g");
    100     svgPicture.setAttribute("id", key);
    101     svgSetPictureData(svgPicture, picture);
    102     return svgPicture;
    103 }
    104 
    105 function 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 
    128 function 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 
    137 function 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 
    173 function 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 
    215 function 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 
    243 function svgSetTextData(svgElement, text) {
    244     svgElement.setAttribute('x', text.x);
    245     svgElement.setAttribute('y', text.y);
    246 }
    247