on master help sign in
Add support for Custom elements in the renderer. Move the CSS transform setters into Utils so they can be used by both elements and forms.
commitf7f137f55304793c4cf137c5f26055a245629284 authorevancz <info@elm-lang.org> dateMon 18 Mar 2013, 00:58 (14 years ago) parent0b0c37c
4 files changed+54−201
libraries/Graphics/Collage.elm+4 runtime/Render/Collage.js+20−175 runtime/Render/Element.js+11−25 runtime/Render/Utils.js+19−1
libraries/Graphics/Collage.elm+4
@@ -5,6 +5,8 @@ import Either
55import Graphics.LineStyle as LS
66import Graphics.Geometry
77import Native.Graphics.Matrix as Matrix
8+import Native.Graphics.Collage as N
9+import Graphics.Element
810
911type Form = { transform : Matrix, form : BasicForm }
1012
@@ -57,3 +59,5 @@ moveY y f = { form = f.form, transform = Matrix.move 0 y f.transform }
5759
5860transform u v w x y z f =
5961 { form = f.form, transform = Matrix.matrix u v w x y z f.transform }
62+
63+collage : Int -> Int -> [Form] -> Element
runtime/Render/Collage.js+20−175
@@ -2,10 +2,11 @@
22ElmRuntime.Render.Collage = function() {
33'use strict';
44
5+var Render = ElmRuntime.use(ElmRuntime.Render.Element);
56var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
67var newElement = Utils.newElement, addTo = Utils.addTo,
78 extract = Utils.extract, fromList = Utils.fromList,
8− fromString = Utils.fromString;
9+ fromString = Utils.fromString, addTransform = Utils.addTransform;
910
1011function trace(ctx, path) {
1112 var points = fromList(path);
@@ -129,9 +130,9 @@ function renderForms(redo, ctx, forms) {
129130}
130131
131132function collageForms(w,h,forms) {
132− var canvas = Render.newElement('canvas');
133− w = ~~w;
134− h = ~~h;
133+ var canvas = newElement('canvas');
134+ w = w|0;
135+ h = h|0;
135136 canvas.style.width = w + 'px';
136137 canvas.style.height = h + 'px';
137138 canvas.style.display = "block";
@@ -143,183 +144,27 @@ function collageForms(w,h,forms) {
143144 renderForms(redo,ctx,w,h,forms);
144145 return canvas;
145146 }
146− canvas.innerHTML = "Your browser does not support the canvas element.";
147+ canvas.innerHTML = "Your browser does not support canvas.";
147148 return canvas;
148149}
149150
150−function applyTransforms(theta,scale,x,y,w,h,e) {
151− var t = "translate(" + (x - w / 2) + "px,"+ (y - h / 2) + "px)";
152− var r = theta === (~~theta) ? "" : "rotate(" + theta*360 + "deg)";
153− var s = scale === 1 ? "" : "scale(" + scale + "," + scale + ")";
154− var transforms = t + " " + s + " " + r;
155− e.style.transform = transforms;
156− e.style.msTransform = transforms;
157− e.style.MozTransform = transforms;
158− e.style.webkitTransform = transforms;
159− e.style.OTransform = transforms;
151+function collageElement(w, h, m, elem) {
152+ var e = Render.render(elem);
153+ var matrix = 'matrix(' + m[0] + ',' + m[3] + ',' + m[1] + ',' +
154+ m[4] + ',' + m[2] + ',' + m[5] + ')';
155+ addTransform(e.style, matrix);
156+ var div = newElement('div');
157+ addTo(div,e);
158+ div.style.width = (w|0) + "px";
159+ div.style.height = (h|0) + "px";
160+ div.style.overflow = "hidden";
161+ return div;
160162}
161163
162−function collageElement(w,h,theta,scale,x,y,elem) {
163− var e = Render.render(elem);
164− applyTransforms(theta,scale,x,y,elem[3],elem[4],e);
165− var div = Render.newElement('div');
166− Render.addTo(div,e);
167− div.style.width = (~~w) + "px";
168− div.style.height = (~~h) + "px";
169− div.style.overflow = "hidden";
170− return div;
164+function render(model) {
165+ return collageForms(model.w, model.h, model.forms);
171166}
172167
173−function collage(w,h,formss) {
174− if (formss.length === 0) { return collageForms(w,h,[]); }
175− var elems = new Array(formss.length);
176− for (var i = formss.length; i--; ) {
177− var f = formss[i];
178− if (typeof f[0] === "string") {
179− elems[i] = collageElement(w,h,f[1],f[2],f[3][1],f[3][2],f[4][1]);
180− } else {
181− elems[i] = collageForms(w,h,f);
182− }
183− }
184− if (formss.length === 1) { return elems[0]; }
185− return Render.flowWith(Render.goIn,function(x){return x},elems);
186−}
187−
188−function updateFormSet(node,currSet,nextSet) {
189− if (Value.eq(nextSet,currSet)) return;
190− var w = node.style.width.slice(0,-2) - 0;
191− var h = node.style.height.slice(0,-2) - 0;
192− if (typeof nextSet[0] === "object") {
193− if (typeof currSet[0] === "object") {
194− if (node.getContext) {
195− var ctx = node.getContext('2d');
196− function redo() { renderForms(this,ctx,w,h,nextSet); }
197− return renderForms(redo,ctx,w,h,nextSet);
198− }
199− }
200− var newNode = collageForms(w,h,nextSet);
201− newNode.style.position = 'absolute';
202− return node.parentNode.replaceChild(newNode,node);
203− }
204− node.style.width = (~~w) + "px";
205− node.style.height = (~~h) + "px";
206− var f = nextSet;
207− var next = nextSet[4][1];
208− Render.update(node.firstChild, currSet[4][1], next);
209− applyTransforms(f[1],f[2],f[3][1],f[3][2],next[3],next[4],node.firstChild);
210−}
211−
212−// assumes that the form sets are the same length.
213−function updateCollage(node,currs,nexts) {
214− if (nexts.length === 1) {
215− return updateFormSet(node,currs[0],nexts[0]);
216− }
217− var kids = node.childNodes;
218− var len = kids.length;
219− for (var i = len; i--; ) {
220− updateFormSet(kids[len-i-1], currs[i], nexts[i]);
221− }
222−}
223−
224−function style(clr,n,list) {
225− return ["Tuple2",
226− '<span style="font-size:100%;color:' + clr + ';">' + n + '</span>',
227− list];
228−}
229−
230−function insideForm(point) { return function(form) {
231− if (!inBoundsOf(point[1],point[2],form)) return false;
232− var hw, hh;
233− switch (form[4][0]) {
234− case "FShape": return insideShape(point,form[1],form[2],form[3],form[4][3][1]);
235− case "FLine": return false;
236− case "FImage":
237− hw = form[4][1] / 2;
238− hh = form[4][2] / 2;
239− break;
240− case "FElement":
241− hw = form[4][1][3] / 2;
242− hh = form[4][1][4] / 2;
243− break;
244− }
245− return insideShape(point,form[1],form[2],form[3],
246− [ [null, hw, hh],
247− [null,-hw, hh],
248− [null,-hw,-hh],
249− [null, hw,-hh],
250− [null, hw, hh] ]);
251− };
252−}
253−
254−function inBoundsOf(px,py,form) {
255− if (form.length < 6) {
256− var fx = form[3][1], fy = form[3][2];
257− var radiusSquared = 0;
258− var scale = form[2];
259− switch (form[4][0]) {
260− case "FShape":
261− var points = form[4][3][1];
262− for (var i = points.length; --i; ) {
263− var p = points[i];
264− radiusSquared = Math.max(radiusSquared, p[1]*p[1] + p[2]*p[2]);
265− }
266− radiusSquared *= scale * scale;
267− break;
268− case "FLine":
269− break;
270− case "FImage":
271− var x = scale * form[4][1] / 2;
272− var y = scale * form[4][2] / 2;
273− radiusSquared = x*x + y*y;
274− break;
275− case "FElement":
276− var x = scale * form[4][1][3] / 2;
277− var y = scale * form[4][1][4] / 2;
278− radiusSquared = x*x + y*y;
279− break;
280− }
281− form.push(function(px,py) {
282− var dx = px - fx;
283− var dy = py - fy;
284− return dx*dx + dy*dy < radiusSquared + 1;
285− });
286− }
287− return form[5](px,py);
288−}
289−
290−function insideShape(point,theta,scale,pos,points) {
291− var counter = 0;
292− var list = ["Nil"];
293− var p1,p2;
294−
295− var x = (point[1] - pos[1]) / scale;
296− var y = (point[2] - pos[2]) / scale;
297− if (theta !== 0) {
298− var t = -2 * Math.PI * theta;
299− var nx = x * Math.cos(t) - y * Math.sin(t);
300− y = x * Math.sin(t) + y * Math.cos(t);
301− x = nx;
302− }
303−
304− if (points.length === 0) { return false; }
305− p1 = points[0];
306− for (var i = points.length - 1; i--; ) {
307− p2 = points[i];
308− var p1x = p1[1], p1y = p1[2], p2x = p2[1], p2y = p2[2];
309−
310− if (p1y < p2y) {var ymin=p1y, ymax=p2y;} else {var ymin=p2y, ymax=p1y;}
311− if (p1x < p2x) {var xmin=p1x, xmax=p2x;} else {var xmin=p2x, xmax=p1x;}
312−
313− if (ymin < y && y <= ymax && x <= xmax) {
314− if (x <= xmin || x <= ((y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x)) {
315− ++counter;
316− }
317− }
318− p1 = p2;
319− }
320− return (counter % 2) === 1;
321−}
322−
323−return {collage:collage, updateCollage:updateCollage, insideForm:insideForm};
168+return { render:render };
324169
325170};
runtime/Render/Element.js+11−25
@@ -2,8 +2,9 @@
22ElmRuntime.Render.Element = function() {
33'use strict';
44
5−var Utils = use(ElmRuntime.Render.Utils);
6−var newElement = Utils.newElement, addTo = Utils.addTo, extract = Utils.extract;
5+var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
6+var newElement = Utils.newElement, addTo = Utils.addTo, extract = Utils.extract,
7+ addTransform = Utils.addTransform, removeTransform = Utils.removeTransform;
78
89function setProps(props, e) {
910 e.style.width = (props.width |0) + 'px';
@@ -117,22 +118,6 @@ function toPos(pos) {
117118 }
118119}
119120
120−function addTransform(style, trans) {
121− style.transform = trans;
122− style.msTransform = trans;
123− style.MozTransform = trans;
124− style.webkitTransform = trans;
125− style.OTransform = trans;
126−}
127−
128−function removeTransform(style) {
129− style.transform = 'none';
130− style.msTransform = 'none';
131− style.MozTransform = 'none';
132− style.webkitTransform = 'none';
133− style.OTransform = 'none';
134−}
135−
136121function setPos(pos,w,h,e) {
137122 e.style.position = 'absolute';
138123 e.style.margin = 'auto';
@@ -169,13 +154,14 @@ function rawHtml(html) {
169154
170155function render(elem) { return setProps(elem.props, makeElement(elem)); }
171156function makeElement(e) {
172− switch(e.element.ctor) {
173− case 'Image': return image(e.props, e.element);
174− case 'Flow': return flow(e.element._0, e.element._1);
175− case 'Container': return container(e.element._0, e.element._1);
157+ var elem = e.element;
158+ switch(elem.ctor) {
159+ case 'Image': return image(e.props, elem);
160+ case 'Flow': return flow(elem._0, elem._1);
161+ case 'Container': return container(elem._0, elem._1);
176162 case 'Spacer': return newElement('div');
177− case 'RawHtml': return rawHtml(e.element._0);
178− case 'DomNode': return e.element._0;
163+ case 'RawHtml': return rawHtml(elem._0);
164+ case 'Custom': return elem.render(elem.model);
179165 }
180166}
181167
@@ -237,7 +223,7 @@ function update(node, curr, next) {
237223 }
238224 setPos(nextE._0, next.props.width, next.props.height, node.firstChild);
239225 break;
240− case "DomNode":
226+ case "Custom":
241227 if (next._0 !== curr._0) node.parentNode.replaceChild(render(next),node);
242228 break;
243229 }
runtime/Render/Utils.js+19−1
@@ -18,6 +18,22 @@ function extract(c) {
1818 return 'rgba(' + c._0 + ',' + c._1 + ',' + c._2 + ',' + c._3 + ')';
1919}
2020
21+function addTransform(style, trans) {
22+ style.transform = trans;
23+ style.msTransform = trans;
24+ style.MozTransform = trans;
25+ style.webkitTransform = trans;
26+ style.OTransform = trans;
27+}
28+
29+function removeTransform(style) {
30+ style.transform = 'none';
31+ style.msTransform = 'none';
32+ style.MozTransform = 'none';
33+ style.webkitTransform = 'none';
34+ style.OTransform = 'none';
35+}
36+
2137var JS = Elm.JavaScript({});
2238
2339return {addTo:addTo,
@@ -25,6 +41,8 @@ return {addTo:addTo,
2541 extract : extract,
2642 fromList: JS.fromList,
2743 fromString: JS.fromString,
28− eq: Elm.Native.Utils({}).eq
44+ eq: Elm.Native.Utils({}).eq,
45+ addTransform: addTransform,
46+ removeTransform: removeTransform
2947 };
3048};