blob: b5907f03404944a382f7bf8d6f52b561eb48a4cb [file] [log] [blame]
caryclark3257c122015-11-16 13:36:08 -08001var 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}