@@ -1,45 +1,29 @@
11
2−ElmRuntime.Render.Collage = function(rts) {
3− /*
4−var JS = Elm.JavaScript;
5−
6−function tracePoints(ctx,points) {
2+ElmRuntime.Render.Collage = function() {
3+'use strict';
4+
5+var Render = ElmRuntime.use(ElmRuntime.Render.Element);
6+var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
7+var newElement = Utils.newElement, addTo = Utils.addTo,
8+ extract = Utils.extract, fromList = Utils.fromList,
9+ fromString = Utils.fromString, addTransform = Utils.addTransform;
10+
11+function trace(ctx, path) {
12+ var points = fromList(path);
13+ console.log(points);
714 var i = points.length - 1;
815 if (i <= 0) return;
9− ctx.moveTo(points[i][1], points[i][2]);
10− while (i--) { ctx.lineTo(points[i][1], points[i][2]); }
16+ ctx.moveTo(points[i]._0, points[i]._1);
17+ while (i--) { ctx.lineTo(points[i]._0, points[i]._1); }
1118}
1219
13−function solid(ctx,color,points) {
14− tracePoints(ctx,points);
15− ctx.strokeStyle = Elm.Color.extract(color);
20+function line(ctx,style,path) {
21+ var isSolid = style.dashing.ctor === 'Nil';
22+ isSolid ? trace(ctx, path) : customLineHelp(ctx, style, path);
1623 ctx.stroke();
17−};
18−
19−function filled(ctx,color,points) {
20− tracePoints(ctx,points);
21− ctx.fillStyle = Elm.Color.extract(color);
22− ctx.fill();
2324}
2425
25−function textured(redo,ctx,src,points) {
26− var img = new Image();
27− img.src = JS.castStringToJSString(src);
28− img.onload = redo;
29−
30− tracePoints(ctx,points);
31− ctx.fillStyle = ctx.createPattern(img,'repeat');
32− ctx.fill();
33−}
34−
35−function customLine(pattern,ctx,color,points) {
36− if (pattern.length === 0) { pattern = [8,4]; }
37− customLineHelp(ctx, pattern, points);
38− ctx.strokeStyle = Elm.Color.extract(color);
39− ctx.stroke();
40−};
41−
42−var customLineHelp = function(ctx, pattern, points) {
26+function customLineHelp(ctx, pattern, points) {
4327 var i = points.length - 1;
4428 if (i <= 0) return;
4529 var x0 = points[i][1], y0 = points[i][2];
@@ -69,249 +53,126 @@ var customLineHelp = function(ctx, pattern, points) {
6953 }
7054 x0 = x1; y0 = y1;
7155 }
72−};
56+}
7357
74−function drawLine(ctx,form) {
75− var points = form[3][1];
76− switch(form[1][0]) {
77− case "Solid" : return solid(ctx,form[2],points);
78− case "Dotted": return customLine([3,3],ctx,form[2],points);
79− case "Dashed": return customLine([8,4],ctx,form[2],points);
80− case "Custom": return customLine(form[1][1],ctx,form[2],points);
81− }
82−};
58+function drawLine(ctx, style, path) {
59+ ctx.lineWidth = style.width;
60+ ctx.lineCap = style.cap.ctor.toLowerCase();
61+ ctx.lineJoin = style.join.ctor.toLowerCase();
62+ ctx.miterLimit = style.miterLimit;
63+ ctx.strokeStyle = extract(style.color);
64+ return line(ctx, style, path);
65+}
8366
84−function drawShape(redo,ctx,shapeStyle,color,points) {
85− switch(shapeStyle[0]) {
86− case "Filled": return filled(ctx,color,points);
87− case "Outlined": return solid(ctx,color,points);
88− case "Textured": return textured(redo,ctx,shapeStyle[1],points);
89− case "CustomOutline":
90− return customLine(shapeStyle[1],ctx,color,points);
67+function texture(redo, ctx, src) {
68+ var img = new Image();
69+ img.src = fromString(src);
70+ img.onload = redo;
71+ return ctx.createPattern(img, 'repeat');
72+}
73+
74+function gradient(ctx, grad) {
75+ var g;
76+ if (grad.ctor === 'Linear') {
77+ var p1 = grad._1, p2 = grad._2;
78+ g = ctx.createLinearGradient(p1._0, p1._1, p2._0, p2._1);
79+ } else {
80+ var p1 = grad._1, p2 = grad._3;
81+ g = ctx.createRadialGradient(p1._0, p1._1, grad._2, p2._0, p2._1, grad._4);
9182 }
92−};
83+ var stops = fromList(grad._0);
84+ for (var i = stops.length; i--; ) {
85+ var stop = stops[i];
86+ g.addColorStop(stop._0, extract(stop._1));
87+ }
88+ return g;
89+}
9390
94−function drawImage(redo,ctx,w,h,src) {
91+function drawShape(redo, ctx, style, path) {
92+ console.log(style, path);
93+ trace(ctx, path);
94+ var sty = style.ctor;
95+ ctx.fillStyle =
96+ sty === 'Solid' ? extract(style._0) :
97+ sty === 'Texture' ? texture(redo, ctx, style._0) : gradient(ctx, style._0);
98+ ctx.fill();
99+}
100+
101+function drawImage(redo, ctx, form) {
95102 var img = new Image();
96103 img.onload = redo;
97− img.src = JS.castStringToJSString(src);
98− ctx.drawImage(img,-w/2,-h/2,w,h);
104+ img.src = fromString(form._3);
105+ var w = form._0, h = form._1, pos = form._2;
106+ console.log(w,h,pos);
107+ ctx.drawImage(img, pos._0, pos._1, w, h, -w/2, -h/2, w, h);
99108}
100109
101−function renderForm(redo,ctx,theta,scale,x,y,form) {
110+function renderForm(redo,ctx,form) {
102111 ctx.save();
103− if (x !== 0 || y !== 0) ctx.translate(x,y);
104− if (theta !== ~~theta) ctx.rotate(2*Math.PI*theta);
105− if (scale !== 1) ctx.scale(scale,scale);
112+ if (form.x !== 0 || form.y !== 0) ctx.translate(form.x, form.y);
113+ if (form.theta !== 0) ctx.rotate(form.theta);
114+ if (form.scale !== 1) ctx.scale(form.scale, form.scale);
106115 ctx.beginPath();
107− switch(form[0]) {
108− case "FLine": drawLine(ctx,form); break;
109− case "FShape": drawShape(redo,ctx,form[1],form[2],form[3][1]); break;
110− case "FImage": drawImage(redo,ctx,form[1],form[2],form[3]); break;
116+ var f = form.form;
117+ console.log(f);
118+ switch(f.ctor) {
119+ case 'FPath' : drawLine(ctx, f._0, f._1); break;
120+ case 'FShape':
121+ if (form.form._0.ctor === 'Left') drawLine(ctx, f._0._0, f._1);
122+ else drawShape(redo, ctx, f._0._0, f._1);
123+ break;
124+ case 'FImage': drawImage(redo, ctx, f); break;
125+ case 'FGroup': renderForms(redo, ctx, f._0); break;
111126 }
112127 ctx.restore();
113−};
128+}
114129
115−function renderForms(redo,ctx,w,h,forms) {
116− ctx.clearRect(0,0,w,h);
117− for (var i = forms.length; i--; ) {
118− var f = forms[i];
119− renderForm(redo,ctx,f[1],f[2],f[3][1],f[3][2],f[4]);
130+function renderForms(redo, ctx, forms) {
131+ var fs = fromList(forms);
132+ console.log(fs);
133+ for (var i = 0, len = fs.length; i < len; ++i) {
134+ renderForm(redo,ctx,fs[i]);
120135 }
121136}
122137
123138function collageForms(w,h,forms) {
124− var canvas = Render.newElement('canvas');
125− w = ~~w;
126− h = ~~h;
139+ var canvas = newElement('canvas');
140+ w = w|0;
141+ h = h|0;
127142 canvas.style.width = w + 'px';
128143 canvas.style.height = h + 'px';
129144 canvas.style.display = "block";
130145 canvas.width = w;
131146 canvas.height = h;
147+ function redo() { renderForms(this,ctx,forms); }
132148 if (canvas.getContext) {
133149 var ctx = canvas.getContext('2d');
134− function redo() { renderForms(this,ctx,w,h,forms); }
135− renderForms(redo,ctx,w,h,forms);
150+ console.log(forms);
151+ renderForms(redo,ctx,forms);
136152 return canvas;
137153 }
138− canvas.innerHTML = "Your browser does not support the canvas element.";
154+ canvas.innerHTML = "Your browser does not support canvas.";
139155 return canvas;
140156}
141157
142−function applyTransforms(theta,scale,x,y,w,h,e) {
143− var t = "translate(" + (x - w / 2) + "px,"+ (y - h / 2) + "px)";
144− var r = theta === (~~theta) ? "" : "rotate(" + theta*360 + "deg)";
145− var s = scale === 1 ? "" : "scale(" + scale + "," + scale + ")";
146− var transforms = t + " " + s + " " + r;
147− e.style.transform = transforms;
148− e.style.msTransform = transforms;
149− e.style.MozTransform = transforms;
150− e.style.webkitTransform = transforms;
151− e.style.OTransform = transforms;
152−}
153−
154−function collageElement(w,h,theta,scale,x,y,elem) {
155− var e = Render.render(elem);
156− applyTransforms(theta,scale,x,y,elem[3],elem[4],e);
157− var div = Render.newElement('div');
158− Render.addTo(div,e);
159− div.style.width = (~~w) + "px";
160− div.style.height = (~~h) + "px";
161− div.style.overflow = "hidden";
162− return div;
158+function collageElement(w, h, m, elem) {
159+ var e = Render.render(elem);
160+ var matrix = 'matrix(' + m[0] + ',' + m[3] + ',' + m[1] + ',' +
161+ m[4] + ',' + m[2] + ',' + m[5] + ')';
162+ addTransform(e.style, matrix);
163+ var div = newElement('div');
164+ addTo(div,e);
165+ div.style.width = (w|0) + "px";
166+ div.style.height = (h|0) + "px";
167+ div.style.overflow = "hidden";
168+ return div;
163169}
164170
165−function collage(w,h,formss) {
166− if (formss.length === 0) { return collageForms(w,h,[]); }
167− var elems = new Array(formss.length);
168− for (var i = formss.length; i--; ) {
169− var f = formss[i];
170− if (typeof f[0] === "string") {
171− elems[i] = collageElement(w,h,f[1],f[2],f[3][1],f[3][2],f[4][1]);
172− } else {
173− elems[i] = collageForms(w,h,f);
174− }
175− }
176− if (formss.length === 1) { return elems[0]; }
177− return Render.flowWith(Render.goIn,function(x){return x},elems);
178−}
179−
180−function updateFormSet(node,currSet,nextSet) {
181− if (Value.eq(nextSet,currSet)) return;
182− var w = node.style.width.slice(0,-2) - 0;
183− var h = node.style.height.slice(0,-2) - 0;
184− if (typeof nextSet[0] === "object") {
185− if (typeof currSet[0] === "object") {
186− if (node.getContext) {
187− var ctx = node.getContext('2d');
188− function redo() { renderForms(this,ctx,w,h,nextSet); }
189− return renderForms(redo,ctx,w,h,nextSet);
190− }
191− }
192− var newNode = collageForms(w,h,nextSet);
193− newNode.style.position = 'absolute';
194− return node.parentNode.replaceChild(newNode,node);
195− }
196− node.style.width = (~~w) + "px";
197− node.style.height = (~~h) + "px";
198− var f = nextSet;
199− var next = nextSet[4][1];
200− Render.update(node.firstChild, currSet[4][1], next);
201− applyTransforms(f[1],f[2],f[3][1],f[3][2],next[3],next[4],node.firstChild);
202−}
203−
204−// assumes that the form sets are the same length.
205−function updateCollage(node,currs,nexts) {
206− if (nexts.length === 1) {
207− return updateFormSet(node,currs[0],nexts[0]);
208− }
209− var kids = node.childNodes;
210− var len = kids.length;
211− for (var i = len; i--; ) {
212− updateFormSet(kids[len-i-1], currs[i], nexts[i]);
213− }
214−}
215−
216−function style(clr,n,list) {
217− return ["Tuple2",
218− '<span style="font-size:100%;color:' + clr + ';">' + n + '</span>',
219− list];
220−}
221−
222−function insideForm(point) { return function(form) {
223− if (!inBoundsOf(point[1],point[2],form)) return false;
224− var hw, hh;
225− switch (form[4][0]) {
226− case "FShape": return insideShape(point,form[1],form[2],form[3],form[4][3][1]);
227− case "FLine": return false;
228− case "FImage":
229− hw = form[4][1] / 2;
230− hh = form[4][2] / 2;
231− break;
232− case "FElement":
233− hw = form[4][1][3] / 2;
234− hh = form[4][1][4] / 2;
235− break;
236− }
237− return insideShape(point,form[1],form[2],form[3],
238− [ [null, hw, hh],
239− [null,-hw, hh],
240− [null,-hw,-hh],
241− [null, hw,-hh],
242− [null, hw, hh] ]);
243− };
171+function render(model) {
172+ console.log(model);
173+ return collageForms(model.w, model.h, model.forms);
244174}
245175
246−function inBoundsOf(px,py,form) {
247− if (form.length < 6) {
248− var fx = form[3][1], fy = form[3][2];
249− var radiusSquared = 0;
250− var scale = form[2];
251− switch (form[4][0]) {
252− case "FShape":
253− var points = form[4][3][1];
254− for (var i = points.length; --i; ) {
255− var p = points[i];
256− radiusSquared = Math.max(radiusSquared, p[1]*p[1] + p[2]*p[2]);
257− }
258− radiusSquared *= scale * scale;
259− break;
260− case "FLine":
261− break;
262− case "FImage":
263− var x = scale * form[4][1] / 2;
264− var y = scale * form[4][2] / 2;
265− radiusSquared = x*x + y*y;
266− break;
267− case "FElement":
268− var x = scale * form[4][1][3] / 2;
269− var y = scale * form[4][1][4] / 2;
270− radiusSquared = x*x + y*y;
271− break;
272− }
273− form.push(function(px,py) {
274− var dx = px - fx;
275− var dy = py - fy;
276− return dx*dx + dy*dy < radiusSquared + 1;
277− });
278− }
279− return form[5](px,py);
280−}
281−
282−function insideShape(point,theta,scale,pos,points) {
283− var counter = 0;
284− var list = ["Nil"];
285− var p1,p2;
286−
287− var x = (point[1] - pos[1]) / scale;
288− var y = (point[2] - pos[2]) / scale;
289− if (theta !== 0) {
290− var t = -2 * Math.PI * theta;
291− var nx = x * Math.cos(t) - y * Math.sin(t);
292− y = x * Math.sin(t) + y * Math.cos(t);
293− x = nx;
294− }
295−
296− if (points.length === 0) { return false; }
297− p1 = points[0];
298− for (var i = points.length - 1; i--; ) {
299− p2 = points[i];
300− var p1x = p1[1], p1y = p1[2], p2x = p2[1], p2y = p2[2];
301−
302− if (p1y < p2y) {var ymin=p1y, ymax=p2y;} else {var ymin=p2y, ymax=p1y;}
303− if (p1x < p2x) {var xmin=p1x, xmax=p2x;} else {var xmin=p2x, xmax=p1x;}
304−
305− if (ymin < y && y <= ymax && x <= xmax) {
306− if (x <= xmin || x <= ((y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x)) {
307− ++counter;
308− }
309− }
310− p1 = p2;
311− }
312− return (counter % 2) === 1;
313−}
176+return { render:render };
314177
315−return {collage:collage, updateCollage:updateCollage, insideForm:insideForm};
316− */
317178};