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.
f7f137fevancz
libraries/Graphics/Collage.elm+4
@@ -5,6 +5,8 @@ import Either
5import Graphics.LineStyle as LS
5import Graphics.LineStyle as LS
6import Graphics.Geometry
6import Graphics.Geometry
7import Native.Graphics.Matrix as Matrix
7import Native.Graphics.Matrix as Matrix
8+import Native.Graphics.Collage as N
9+import Graphics.Element
8
10
9type Form = { transform : Matrix, form : BasicForm }
11type Form = { transform : Matrix, form : BasicForm }
10
12
@@ -57,3 +59,5 @@ moveY y f = { form = f.form, transform = Matrix.move 0 y f.transform }
57
59
58transform u v w x y z f =
60transform u v w x y z f =
59 { form = f.form, transform = Matrix.matrix u v w x y z f.transform }
61 { 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 @@
2ElmRuntime.Render.Collage = function() {
2ElmRuntime.Render.Collage = function() {
3'use strict';
3'use strict';
4
4
5+var Render = ElmRuntime.use(ElmRuntime.Render.Element);
5var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
6var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
6var newElement = Utils.newElement, addTo = Utils.addTo,
7var newElement = Utils.newElement, addTo = Utils.addTo,
7 extract = Utils.extract, fromList = Utils.fromList,
8 extract = Utils.extract, fromList = Utils.fromList,
8− fromString = Utils.fromString;
9+ fromString = Utils.fromString, addTransform = Utils.addTransform;
9
10
10function trace(ctx, path) {
11function trace(ctx, path) {
11 var points = fromList(path);
12 var points = fromList(path);
@@ -129,9 +130,9 @@ function renderForms(redo, ctx, forms) {
129}
130}
130
131
131function collageForms(w,h,forms) {
132function collageForms(w,h,forms) {
132− var canvas = Render.newElement('canvas');
133+ var canvas = newElement('canvas');
133− w = ~~w;
134+ w = w|0;
134− h = ~~h;
135+ h = h|0;
135 canvas.style.width = w + 'px';
136 canvas.style.width = w + 'px';
136 canvas.style.height = h + 'px';
137 canvas.style.height = h + 'px';
137 canvas.style.display = "block";
138 canvas.style.display = "block";
@@ -143,183 +144,27 @@ function collageForms(w,h,forms) {
143 renderForms(redo,ctx,w,h,forms);
144 renderForms(redo,ctx,w,h,forms);
144 return canvas;
145 return canvas;
145 }
146 }
146− canvas.innerHTML = "Your browser does not support the canvas element.";
147+ canvas.innerHTML = "Your browser does not support canvas.";
147 return canvas;
148 return canvas;
148}
149}
149
150
150−function applyTransforms(theta,scale,x,y,w,h,e) {
151+function collageElement(w, h, m, elem) {
151− var t = "translate(" + (x - w / 2) + "px,"+ (y - h / 2) + "px)";
152+ var e = Render.render(elem);
152− var r = theta === (~~theta) ? "" : "rotate(" + theta*360 + "deg)";
153+ var matrix = 'matrix(' + m[0] + ',' + m[3] + ',' + m[1] + ',' +
153− var s = scale === 1 ? "" : "scale(" + scale + "," + scale + ")";
154+ m[4] + ',' + m[2] + ',' + m[5] + ')';
154− var transforms = t + " " + s + " " + r;
155+ addTransform(e.style, matrix);
155− e.style.transform = transforms;
156+ var div = newElement('div');
156− e.style.msTransform = transforms;
157+ addTo(div,e);
157− e.style.MozTransform = transforms;
158+ div.style.width = (w|0) + "px";
158− e.style.webkitTransform = transforms;
159+ div.style.height = (h|0) + "px";
159− e.style.OTransform = transforms;
160+ div.style.overflow = "hidden";
161+ return div;
160}
162}
161
163
162−function collageElement(w,h,theta,scale,x,y,elem) {
164+function render(model) {
163− var e = Render.render(elem);
165+ return collageForms(model.w, model.h, model.forms);
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;
171}
166}
172
167
173−function collage(w,h,formss) {
168+return { render:render };
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};
324
169
325};
170};
runtime/Render/Element.js+11−25
@@ -2,8 +2,9 @@
2ElmRuntime.Render.Element = function() {
2ElmRuntime.Render.Element = function() {
3'use strict';
3'use strict';
4
4
5−var Utils = use(ElmRuntime.Render.Utils);
5+var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
6−var newElement = Utils.newElement, addTo = Utils.addTo, extract = Utils.extract;
6+var newElement = Utils.newElement, addTo = Utils.addTo, extract = Utils.extract,
7+ addTransform = Utils.addTransform, removeTransform = Utils.removeTransform;
7
8
8function setProps(props, e) {
9function setProps(props, e) {
9 e.style.width = (props.width |0) + 'px';
10 e.style.width = (props.width |0) + 'px';
@@ -117,22 +118,6 @@ function toPos(pos) {
117 }
118 }
118}
119}
119
120
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−
136function setPos(pos,w,h,e) {
121function setPos(pos,w,h,e) {
137 e.style.position = 'absolute';
122 e.style.position = 'absolute';
138 e.style.margin = 'auto';
123 e.style.margin = 'auto';
@@ -169,13 +154,14 @@ function rawHtml(html) {
169
154
170function render(elem) { return setProps(elem.props, makeElement(elem)); }
155function render(elem) { return setProps(elem.props, makeElement(elem)); }
171function makeElement(e) {
156function makeElement(e) {
157+ var elem = e.element;
172− switch(e.element.ctor) {
158+ switch(elem.ctor) {
173− case 'Image': return image(e.props, e.element);
159+ case 'Image': return image(e.props, elem);
174− case 'Flow': return flow(e.element._0, e.element._1);
160+ case 'Flow': return flow(elem._0, elem._1);
175− case 'Container': return container(e.element._0, e.element._1);
161+ case 'Container': return container(elem._0, elem._1);
176 case 'Spacer': return newElement('div');
162 case 'Spacer': return newElement('div');
177− case 'RawHtml': return rawHtml(e.element._0);
163+ case 'RawHtml': return rawHtml(elem._0);
178− case 'DomNode': return e.element._0;
164+ case 'Custom': return elem.render(elem.model);
179 }
165 }
180}
166}
181
167
@@ -237,7 +223,7 @@ function update(node, curr, next) {
237 }
223 }
238 setPos(nextE._0, next.props.width, next.props.height, node.firstChild);
224 setPos(nextE._0, next.props.width, next.props.height, node.firstChild);
239 break;
225 break;
240− case "DomNode":
226+ case "Custom":
241 if (next._0 !== curr._0) node.parentNode.replaceChild(render(next),node);
227 if (next._0 !== curr._0) node.parentNode.replaceChild(render(next),node);
242 break;
228 break;
243 }
229 }
runtime/Render/Utils.js+19−1
@@ -18,6 +18,22 @@ function extract(c) {
18 return 'rgba(' + c._0 + ',' + c._1 + ',' + c._2 + ',' + c._3 + ')';
18 return 'rgba(' + c._0 + ',' + c._1 + ',' + c._2 + ',' + c._3 + ')';
19}
19}
20
20
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+
21var JS = Elm.JavaScript({});
37var JS = Elm.JavaScript({});
22
38
23return {addTo:addTo,
39return {addTo:addTo,
@@ -25,6 +41,8 @@ return {addTo:addTo,
25 extract : extract,
41 extract : extract,
26 fromList: JS.fromList,
42 fromList: JS.fromList,
27 fromString: JS.fromString,
43 fromString: JS.fromString,
28− eq: Elm.Native.Utils({}).eq
44+ eq: Elm.Native.Utils({}).eq,
45+ addTransform: addTransform,
46+ removeTransform: removeTransform
29 };
47 };
30};
48};