@@ -3,6 +3,7 @@ ElmRuntime.Render.Collage = function() {
33'use strict';
44
55var Render = ElmRuntime.use(ElmRuntime.Render.Element);
6+var Matrix = Elm.Matrix2D({});
67var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
78var newElement = Utils.newElement, addTo = Utils.addTo,
89 extract = Utils.extract, fromList = Utils.fromList,
@@ -112,7 +113,7 @@ function drawImage(redo, ctx, form) {
112113 ctx.drawImage(img, pos._0, pos._1, w, h, -w/2, -h/2, w, h);
113114}
114115
115−function renderForm(stack, redo, ctx, form) {
116+function renderForm(redo, ctx, form) {
116117 ctx.save();
117118 var x = form.x, y = form.y, theta = form.theta, scale = form.scale;
118119 if (x !== 0 || y !== 0) ctx.translate(x, -y);
@@ -131,73 +132,121 @@ function renderForm(stack, redo, ctx, form) {
131132 }
132133 break;
133134 case 'FImage': drawImage(redo, ctx, f); break;
134− case 'FGroup':
135− ctx.save();
136− var m = f._0;
137− // stack.push(makeTransform(x, y, theta, scale, m));
138− ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
139− renderForms(stack, redo, ctx, f._1);
140− // stack.pop();
141− ctx.restore();
142− break;
143135 }
144136 ctx.restore();
145137}
146138
147−function makeTransform(x, y, theta, scale, matrix) {
148− return function(m) {
149− if (x !== 0 || y !== 0) m = A3( Matrix.move, x, y, m );
150− if (theta !== 0) m = A2( Matrix.rotate, theta, m );
151− if (scale !== 1) m = Matrix.scale( scale );
152− return Matrix.multiply( m, matrix );
153− };
139+function makeTransform(form, matrix) {
140+ var m = matrix;
141+ var x = form.x, y = form.y, theta = form.theta, scale = form.scale;
142+ if (x !== 0 || y !== 0) m = A3( Matrix.move, x, y, m );
143+ if (theta !== 0) m = A2( Matrix.rotate, theta, m );
144+ if (scale !== 1) m = Matrix.scale( scale );
145+ return m;
154146}
155147
156−function renderForms(stack, redo, ctx, forms) {
157− var fs = fromList(forms);
158− for (var i = 0, len = fs.length; i < len; ++i) {
159− renderForm(stack, redo, ctx, fs[i]);
148+function collageElement(width, height, matrices, form) {
149+ var elem = form.form._0,
150+ e = Render.render(elem),
151+ m = A6( Matrix.matrix, 1, 0, 0, 1,
152+ (width - elem.props.width)/2,
153+ (elem.props.height - height)/2 );
154+ var len = matrices.length;
155+ for (var i = 0; i < len; ++i) { m = A2( Matrix.multiply, m, matrices[i] ); }
156+ m = makeTransform(form, m);
157+ var mtrx = 'matrix(' + m[0] + ',' + m[3] + ',' + m[1] + ',' +
158+ m[4] + ',' + m[2] + ',' + (-m[5]) + ')';
159+ addTransform(e.style, mtrx);
160+ var div = newElement('div');
161+ addTo(div,e);
162+ div.style.width = width + 'px';
163+ div.style.height = height + 'px';
164+ div.style.overflow = 'hidden';
165+ div.style.position = 'absolute';
166+ return div;
167+}
168+
169+function stepperHelp(group) {
170+ var i = 0;
171+ function hasNext() { return i < group.length; }
172+ // assumes that there is a next element
173+ function next() {
174+ var out = group[i];
175+ ++i;
176+ return out;
177+ }
178+ return { hasNext:hasNext, next:next };
179+}
180+
181+function stepper(forms) {
182+ var ps = [stepperHelp(fromList(forms))];
183+ var matrices = [];
184+ function hasNext() {
185+ var len = ps.length;
186+ for (var i = 0; i < len; ++i ) {
187+ if (ps[i].hasNext()) return true;
188+ }
189+ return false;
160190 }
191+ // assumes that there is a next element
192+ function next(ctx) {
193+ while (!ps[0].hasNext()) { ps.shift(); matrices.pop(); ctx.restore(); }
194+ var out = ps[0].next();
195+ if (out.ctor === 'FGroup') {
196+ ps.unshift(stepperHelp(out._1));
197+ matrices.push(out._0);
198+ ctx.save();
199+ var m = f._0;
200+ ctx.transform(m[0], m[3], m[1], m[4], m[2], -m[5]);
201+ }
202+ return out;
203+ }
204+ function transforms() { return matrices; }
205+ return { hasNext:hasNext, next:next, transforms:transforms };
161206}
162207
163−function collageForms(w,h,forms) {
208+function makeCanvas(w,h) {
164209 var canvas = newElement('canvas');
165210 canvas.style.width = w + 'px';
166211 canvas.style.height = h + 'px';
167212 canvas.style.display = "block";
213+ canvas.style.position = "absolute";
168214 canvas.width = w;
169215 canvas.height = h;
170− function redo() { renderForms([], this, ctx, forms); }
171− if (canvas.getContext) {
172− var ctx = canvas.getContext('2d');
173− ctx.translate(w/2, h/2);
174− renderForms([], redo, ctx, forms);
175− return canvas;
176− }
177− canvas.innerHTML = "Your browser does not support canvas.";
178216 return canvas;
179217}
180218
181−function collageElement(stack, width, height, elem) {
182− var e = Render.render(elem),
183− w = elem.props.width,
184− h = elem.props.height,
185− m = Matrix.matrix(1,0,0,1,width/2,height/2),
186− len = stack.length;
187− for (var i = 0; i < len; ++i) { m = stack[i](m); }
188− var mtrx = 'matrix(' + m[0] + ',' + m[3] + ',' + m[1] + ',' +
189− m[4] + ',' + m[2] + ',' + m[5] + ')';
190− addTransform(e.style, 'translate(' + (-w/2) + 'px,'+ (-h/2) + 'px) ' + mtrx);
191− var div = newElement('div');
192− addTo(div,e);
193− div.style.width = width + 'px';
194− div.style.height = height + 'px';
195− div.style.overflow = 'hidden';
196− return div;
197−}
198−
199219function render(model) {
200− return collageForms(model.w, model.h, model.forms);
220+ var w = model.w,
221+ h = model.h,
222+ div = newElement('div'),
223+ canvas = makeCanvas(w,h),
224+ ctx = canvas.getContext('2d');
225+ div.appendChild(canvas);
226+ ctx.translate(w/2, h/2);
227+
228+ var stpr = stepper(model.forms);
229+ while (stpr.hasNext()) {
230+ var form = stpr.next(ctx);
231+ if (form.form.ctor === 'FElement') {
232+ div.appendChild(collageElement(w, h, stpr.transforms(), form));
233+ if (!stpr.hasNext()) return div;
234+ canvas = makeCanvas(w,h);
235+ div.appendChild(canvas);
236+ ctx = canvas.getContext('2d');
237+ ctx.translate(w/2, h/2);
238+ var transforms = stpr.transforms();
239+ var len = transforms.length;
240+ for (var i = 0; i < len; ++i) {
241+ var m = transforms[i];
242+ ctx.save();
243+ ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
244+ }
245+ } else if (form.form.ctor !== 'FGroup') {
246+ renderForm(function() { update(div, model, model); }, ctx, form);
247+ }
248+ }
249+ return div;
201250}
202251
203252function update(node, oldModel, newModel) {
@@ -207,8 +256,6 @@ function update(node, oldModel, newModel) {
207256 var ctx = node.getContext('2d');
208257 var w = newModel.w, h = newModel.h;
209258 ctx.clearRect(-w/2, -h/2, w, h);
210− function redo() { renderForms( [], this, ctx, newModel.forms ); }
211− renderForms( [], redo, ctx, newModel.forms );
212259}
213260
214261return { render:render, update:update };