on master help sign in
Support `toForm` in all cases.
commite1425af666cfec817dd8f6bd9fd470f4af9be399 authorevancz <info@elm-lang.org> dateMon 13 May 2013, 16:38 (13 years ago) parentdc3b220
2 files changed+121−71
runtime/Render/Collage.js+114−64 runtime/Render/Element.js+7−7
runtime/Render/Collage.js+114−64
@@ -5,7 +5,7 @@ ElmRuntime.Render.Collage = function() {
55var Render = ElmRuntime.use(ElmRuntime.Render.Element);
66var Matrix = Elm.Matrix2D({});
77var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
8−var newElement = Utils.newElement, addTo = Utils.addTo,
8+var newElement = Utils.newElement,
99 extract = Utils.extract, fromList = Utils.fromList,
1010 fromString = Utils.fromString, addTransform = Utils.addTransform;
1111
@@ -136,75 +136,68 @@ function renderForm(redo, ctx, form) {
136136 ctx.restore();
137137}
138138
139−function makeTransform(form, matrix) {
140− var m = matrix;
139+function makeTransform(w, h, form, matrices) {
140+ var props = form.form._0.props;
141+ var m = A6( Matrix.matrix, 1, 0, 0, 1,
142+ (w - props.width)/2,
143+ (props.height - h)/2 );
144+ var len = matrices.length;
145+ for (var i = 0; i < len; ++i) { m = A2( Matrix.multiply, m, matrices[i] ); }
146+
141147 var x = form.x, y = form.y, theta = form.theta, scale = form.scale;
142148 if (x !== 0 || y !== 0) m = A3( Matrix.move, x, y, m );
143149 if (theta !== 0) m = A2( Matrix.rotate, theta, m );
144150 if (scale !== 1) m = Matrix.scale( scale );
145− return m;
146−}
147−
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;
151+ return 'matrix(' + m[0] + ',' + m[3] + ',' + m[1] + ',' +
152+ m[4] + ',' + m[2] + ',' + (-m[5]) + ')';
167153}
168154
169155function stepperHelp(list) {
170156 var arr = fromList(list);
171157 var i = 0;
172− function hasNext() { return i < arr.length; }
158+ function peekNext() {
159+ return i < arr.length ? arr[i].form.ctor : '';
160+ }
173161 // assumes that there is a next element
174162 function next() {
175163 var out = arr[i];
176164 ++i;
177165 return out;
178166 }
179− return { hasNext:hasNext, next:next };
167+ return { peekNext:peekNext, next:next };
180168}
181169
182170function stepper(forms) {
183171 var ps = [stepperHelp(forms)];
184172 var matrices = [];
185− function hasNext() {
173+ function peekNext() {
186174 var len = ps.length;
175+ var formType = '';
187176 for (var i = 0; i < len; ++i ) {
188− if (ps[i].hasNext()) return true;
177+ if (formType = ps[i].peekNext()) return formType;
189178 }
190− return false;
179+ return '';
191180 }
192181 // assumes that there is a next element
193182 function next(ctx) {
194− while (!ps[0].hasNext()) { ps.shift(); matrices.pop(); ctx.restore(); }
183+ while (!ps[0].peekNext()) { ps.shift(); matrices.pop(); ctx.restore(); }
195184 var out = ps[0].next();
196185 var f = out.form;
197186 if (f.ctor === 'FGroup') {
198187 ps.unshift(stepperHelp(f._1));
199188 var m = f._0;
200189 matrices.push(m);
190+ var x = out.x, y = out.y, theta = out.theta, scale = out.scale;
191+ if (x !== 0 || y !== 0) ctx.translate(x, -y);
192+ if (theta !== 0) ctx.rotate(theta);
193+ if (scale !== 1) ctx.scale(scale, scale);
201194 ctx.save();
202195 ctx.transform(m[0], m[3], m[1], m[4], m[2], -m[5]);
203196 }
204197 return out;
205198 }
206199 function transforms() { return matrices; }
207− return { hasNext:hasNext, next:next, transforms:transforms };
200+ return { peekNext:peekNext, next:next, transforms:transforms };
208201}
209202
210203function makeCanvas(w,h) {
@@ -219,45 +212,102 @@ function makeCanvas(w,h) {
219212}
220213
221214function render(model) {
222− var w = model.w,
223− h = model.h,
224− div = newElement('div'),
225− canvas = makeCanvas(w,h),
226− ctx = canvas.getContext('2d');
227− div.appendChild(canvas);
228− ctx.translate(w/2, h/2);
215+ var div = newElement('div');
216+ update(div, model, model);
217+ return div;
218+}
229219
230− var stpr = stepper(model.forms);
231− while (stpr.hasNext()) {
232− var form = stpr.next(ctx);
233− if (form.form.ctor === 'FElement') {
234− div.appendChild(collageElement(w, h, stpr.transforms(), form));
235− if (!stpr.hasNext()) return div;
236− canvas = makeCanvas(w,h);
237− div.appendChild(canvas);
238− ctx = canvas.getContext('2d');
239− ctx.translate(w/2, h/2);
240− var transforms = stpr.transforms();
241− var len = transforms.length;
242− for (var i = 0; i < len; ++i) {
243− var m = transforms[i];
244− ctx.save();
245− ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
220+function updateTracker(w,h,div) {
221+ var kids = div.childNodes;
222+ var i = 0;
223+ function transform(transforms, ctx) {
224+ ctx.translate(w/2, h/2);
225+ var len = transforms.length;
226+ for (var i = 0; i < len; ++i) {
227+ var m = transforms[i];
228+ ctx.save();
229+ ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
230+ }
231+ return ctx;
232+ }
233+ function getContext(transforms) {
234+ while (i < kids.length) {
235+ var node = kids[i++];
236+ if (node.getContext) {
237+ node.width = w;
238+ node.height = h;
239+ return transform(transforms, node.getContext('2d'));
246240 }
247− } else if (form.form.ctor !== 'FGroup') {
248− renderForm(function() { update(div, model, model); }, ctx, form);
241+ div.removeChild(node);
249242 }
243+ var canvas = makeCanvas(w,h);
244+ div.appendChild(canvas);
245+ // we have added a new node, so we must step our position
246+ ++i;
247+ return transform(transforms, canvas.getContext('2d'));
250248 }
251− return div;
249+ function element(matrices, form) {
250+ var container = kids[i];
251+ if (!container) {
252+ container = newElement('div');
253+ container.style.overflow = 'hidden';
254+ container.style.position = 'absolute';
255+ div.appendChild(container);
256+ } else if (container.getContext) {
257+ container = newElement('div');
258+ container.style.overflow = 'hidden';
259+ container.style.position = 'absolute';
260+ div.insertBefore(container, kids[i]);
261+ }
262+ // we have added a new node, so we must step our position
263+ ++i;
264+
265+ container.style.width = w + 'px';
266+ container.style.height = h + 'px';
267+
268+ var elem = form.form._0;
269+ var node = container.firstChild;
270+ if (node) {
271+ Render.update(node, node.oldElement, elem);
272+ } else {
273+ node = Render.render(elem);
274+ container.appendChild(node);
275+ }
276+ node.oldElement = elem;
277+ addTransform(node.style, makeTransform(w, h, form, matrices));
278+ }
279+ return { getContext:getContext, element:element };
252280}
253281
254−function update(node, oldModel, newModel) {
255− if (!node.getContext) {
256− return node.parentNode.replaceChild(render(newModel), node);
282+
283+function update(div, _, model) {
284+ var w = model.w;
285+ var h = model.h;
286+ div.style.width = w + 'px';
287+ div.style.height = h + 'px';
288+ if (model.forms.ctor === 'Nil') {
289+ while (div.hasChildNodes()) {
290+ div.removeChild(div.lastChild);
291+ }
257292 }
258− var ctx = node.getContext('2d');
259− var w = newModel.w, h = newModel.h;
260− ctx.clearRect(-w/2, -h/2, w, h);
293+ var stpr = stepper(model.forms);
294+ var tracker = updateTracker(w,h,div);
295+ var ctx = null;
296+ var formType = '';
297+
298+ while (formType = stpr.peekNext()) {
299+ if (ctx === null && formType !== 'FElement') {
300+ ctx = tracker.getContext(stpr.transforms());
301+ }
302+ var form = stpr.next(ctx);
303+ if (formType === 'FElement') {
304+ tracker.element(stpr.transforms(), form);
305+ ctx = null;
306+ } else if (formType !== 'FGroup') {
307+ renderForm(function() { update(div, model, model); }, ctx, form);
308+ }
309+ }
310+ return div;
261311}
262312
263313return { render:render, update:update };
runtime/Render/Element.js+7−7
@@ -3,7 +3,7 @@ ElmRuntime.Render.Element = function() {
33'use strict';
44
55var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
6−var newElement = Utils.newElement, addTo = Utils.addTo, extract = Utils.extract,
6+var newElement = Utils.newElement, extract = Utils.extract,
77 addTransform = Utils.addTransform, removeTransform = Utils.removeTransform,
88 fromList = Utils.fromList, eq = Utils.eq;
99
@@ -18,7 +18,7 @@ function setProps(props, e) {
1818 if (props.href !== '') {
1919 var a = newElement('a');
2020 a.href = props.href;
21− addTo(a,e);
21+ a.appendChild(e);
2222 return a;
2323 }
2424 return e;
@@ -63,7 +63,7 @@ function fittedImage(w, h, src) {
6363 };
6464 img.src = src;
6565 img.name = src;
66− addTo(e,img);
66+ e.appendChild(img);
6767 return e;
6868}
6969
@@ -85,7 +85,7 @@ function croppedImage(elem, w, h, src) {
8585 };
8686 img.src = src;
8787 img.name = src;
88− addTo(e,img);
88+ e.appendChild(img);
8989 return e;
9090}
9191
@@ -95,7 +95,7 @@ function goRight(e) { e.style.styleFloat = e.style.cssFloat = "left"; return e;
9595function flowWith(f, array) {
9696 var container = newElement('div');
9797 for (var i = array.length; i--; ) {
98− addTo(container, f(render(array[i])));
98+ container.appendChild(f(render(array[i])));
9999 }
100100 return container;
101101}
@@ -143,7 +143,7 @@ function container(pos,elem) {
143143 var div = newElement('div');
144144 div.style.position = 'relative';
145145 div.style.overflow = 'hidden';
146− addTo(div,e);
146+ div.appendChild(e);
147147 return div;
148148}
149149
@@ -256,7 +256,7 @@ function updateProps(node, curr, next) {
256256 if (currP.href === '') {
257257 var a = newElement('a');
258258 a.href = props.href;
259− addTo(a,e);
259+ a.appendChild(e);
260260 e.parentNode.replaceChild(a,e);
261261 } else {
262262 node.parentNode.href = props.href;