@@ -112,11 +112,12 @@ function drawImage(redo, ctx, form) {
112112 ctx.drawImage(img, pos._0, pos._1, w, h, -w/2, -h/2, w, h);
113113}
114114
115−function renderForm(redo,ctx,form) {
115+function renderForm(stack, redo, ctx, form) {
116116 ctx.save();
117− if (form.x !== 0 || form.y !== 0) ctx.translate(form.x, -form.y);
118− if (form.theta !== 0) ctx.rotate(form.theta);
119− if (form.scale !== 1) ctx.scale(form.scale, form.scale);
117+ var x = form.x, y = form.y, theta = form.theta, scale = form.scale;
118+ if (x !== 0 || y !== 0) ctx.translate(x, -y);
119+ if (theta !== 0) ctx.rotate(theta);
120+ if (scale !== 1) ctx.scale(scale, scale);
120121 ctx.beginPath();
121122 var f = form.form;
122123 switch(f.ctor) {
@@ -126,25 +127,36 @@ function renderForm(redo,ctx,form) {
126127 f._1.closed = true;
127128 drawLine(ctx, f._0._0, f._1);
128129 } else {
129− drawShape(redo, ctx, f._0._0, f._1);
130− }
130+ drawShape(redo, ctx, f._0._0, f._1);
131+ }
131132 break;
132133 case 'FImage': drawImage(redo, ctx, f); break;
133134 case 'FGroup':
134135 ctx.save();
135136 var m = f._0;
137+ // stack.push(makeTransform(x, y, theta, scale, m));
136138 ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
137− renderForms(redo, ctx, f._1);
139+ renderForms(stack, redo, ctx, f._1);
140+ // stack.pop();
138141 ctx.restore();
139142 break;
140143 }
141144 ctx.restore();
142145}
143146
144−function renderForms(redo, ctx, forms) {
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+ };
154+}
155+
156+function renderForms(stack, redo, ctx, forms) {
145157 var fs = fromList(forms);
146158 for (var i = 0, len = fs.length; i < len; ++i) {
147− renderForm(redo, ctx, fs[i]);
159+ renderForm(stack, redo, ctx, fs[i]);
148160 }
149161}
150162
@@ -155,27 +167,27 @@ function collageForms(w,h,forms) {
155167 canvas.style.display = "block";
156168 canvas.width = w;
157169 canvas.height = h;
158− function redo() { renderForms(this,ctx,forms); }
170+ function redo() { renderForms([], this, ctx, forms); }
159171 if (canvas.getContext) {
160172 var ctx = canvas.getContext('2d');
161173 ctx.translate(w/2, h/2);
162− renderForms(redo,ctx,forms);
174+ renderForms([], redo, ctx, forms);
163175 return canvas;
164176 }
165177 canvas.innerHTML = "Your browser does not support canvas.";
166178 return canvas;
167179}
168180
169−function collageElement(width, height, x, y, theta, scale, elem) {
170− var e = Render.render(elem);
171− var w = elem.props.width,
181+function collageElement(stack, width, height, elem) {
182+ var e = Render.render(elem),
183+ w = elem.props.width,
172184 h = elem.props.height,
173− t = 'translate(' + (width + f.x - w/2) + 'px,'+ (height - f.y - h/2) + 'px)',
174− r = theta === 0 ? '' : 'rotate(' + theta + 'rad)',
175− s = scale === 1 ? '' : 'scale(' + scale + ',' + scale + ')';
176− // var m = 'matrix(' + mtrx[0] + ',' + mtrx[3] + ',' + mtrx[1] + ',' +
177− // mtrx[4] + ',' + mtrx[2] + ',' + mtrx[5] + ')';
178− addTransform(e.style, t + ' ' + s + ' ' + r);
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);
179191 var div = newElement('div');
180192 addTo(div,e);
181193 div.style.width = width + 'px';
@@ -195,8 +207,8 @@ function update(node, oldModel, newModel) {
195207 var ctx = node.getContext('2d');
196208 var w = newModel.w, h = newModel.h;
197209 ctx.clearRect(-w/2, -h/2, w, h);
198− function redo() { renderForms( this, ctx, newModel.forms ); }
199− renderForms( redo, ctx, newModel.forms );
210+ function redo() { renderForms( [], this, ctx, newModel.forms ); }
211+ renderForms( [], redo, ctx, newModel.forms );
200212}
201213
202214return { render:render, update:update };