on master help sign in
Support `toForm` in all cases.
e1425afevancz
runtime/Render/Collage.js+114−64
@@ -5,7 +5,7 @@ ElmRuntime.Render.Collage = function() {
5var Render = ElmRuntime.use(ElmRuntime.Render.Element);
5var Render = ElmRuntime.use(ElmRuntime.Render.Element);
6var Matrix = Elm.Matrix2D({});
6var Matrix = Elm.Matrix2D({});
7var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
7var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
8−var newElement = Utils.newElement, addTo = Utils.addTo,
8+var newElement = Utils.newElement,
9 extract = Utils.extract, fromList = Utils.fromList,
9 extract = Utils.extract, fromList = Utils.fromList,
10 fromString = Utils.fromString, addTransform = Utils.addTransform;
10 fromString = Utils.fromString, addTransform = Utils.addTransform;
11
11
@@ -136,75 +136,68 @@ function renderForm(redo, ctx, form) {
136 ctx.restore();
136 ctx.restore();
137}
137}
138
138
139−function makeTransform(form, matrix) {
139+function makeTransform(w, h, form, matrices) {
140+ var props = form.form._0.props;
140− var m = matrix;
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+
141 var x = form.x, y = form.y, theta = form.theta, scale = form.scale;
147 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 );
148 if (x !== 0 || y !== 0) m = A3( Matrix.move, x, y, m );
143 if (theta !== 0) m = A2( Matrix.rotate, theta, m );
149 if (theta !== 0) m = A2( Matrix.rotate, theta, m );
144 if (scale !== 1) m = Matrix.scale( scale );
150 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] + ',' +
151+ return 'matrix(' + m[0] + ',' + m[3] + ',' + m[1] + ',' +
158− m[4] + ',' + m[2] + ',' + (-m[5]) + ')';
152+ 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}
153}
168
154
169function stepperHelp(list) {
155function stepperHelp(list) {
170 var arr = fromList(list);
156 var arr = fromList(list);
171 var i = 0;
157 var i = 0;
158+ function peekNext() {
172− function hasNext() { return i < arr.length; }
159+ return i < arr.length ? arr[i].form.ctor : '';
160+ }
173 // assumes that there is a next element
161 // assumes that there is a next element
174 function next() {
162 function next() {
175 var out = arr[i];
163 var out = arr[i];
176 ++i;
164 ++i;
177 return out;
165 return out;
178 }
166 }
179− return { hasNext:hasNext, next:next };
167+ return { peekNext:peekNext, next:next };
180}
168}
181
169
182function stepper(forms) {
170function stepper(forms) {
183 var ps = [stepperHelp(forms)];
171 var ps = [stepperHelp(forms)];
184 var matrices = [];
172 var matrices = [];
185− function hasNext() {
173+ function peekNext() {
186 var len = ps.length;
174 var len = ps.length;
175+ var formType = '';
187 for (var i = 0; i < len; ++i ) {
176 for (var i = 0; i < len; ++i ) {
188− if (ps[i].hasNext()) return true;
177+ if (formType = ps[i].peekNext()) return formType;
189 }
178 }
190− return false;
179+ return '';
191 }
180 }
192 // assumes that there is a next element
181 // assumes that there is a next element
193 function next(ctx) {
182 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(); }
195 var out = ps[0].next();
184 var out = ps[0].next();
196 var f = out.form;
185 var f = out.form;
197 if (f.ctor === 'FGroup') {
186 if (f.ctor === 'FGroup') {
198 ps.unshift(stepperHelp(f._1));
187 ps.unshift(stepperHelp(f._1));
199 var m = f._0;
188 var m = f._0;
200 matrices.push(m);
189 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);
201 ctx.save();
194 ctx.save();
202 ctx.transform(m[0], m[3], m[1], m[4], m[2], -m[5]);
195 ctx.transform(m[0], m[3], m[1], m[4], m[2], -m[5]);
203 }
196 }
204 return out;
197 return out;
205 }
198 }
206 function transforms() { return matrices; }
199 function transforms() { return matrices; }
207− return { hasNext:hasNext, next:next, transforms:transforms };
200+ return { peekNext:peekNext, next:next, transforms:transforms };
208}
201}
209
202
210function makeCanvas(w,h) {
203function makeCanvas(w,h) {
@@ -219,45 +212,102 @@ function makeCanvas(w,h) {
219}
212}
220
213
221function render(model) {
214function render(model) {
222− var w = model.w,
223− h = model.h,
224− div = newElement('div'),
215+ var div = newElement('div');
225− canvas = makeCanvas(w,h),
216+ update(div, model, model);
226− ctx = canvas.getContext('2d');
217+ return div;
227− div.appendChild(canvas);
218+}
228− ctx.translate(w/2, h/2);
229
219
230− var stpr = stepper(model.forms);
220+function updateTracker(w,h,div) {
231− while (stpr.hasNext()) {
221+ var kids = div.childNodes;
232− var form = stpr.next(ctx);
222+ var i = 0;
233− if (form.form.ctor === 'FElement') {
223+ function transform(transforms, ctx) {
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);
224+ ctx.translate(w/2, h/2);
240− var transforms = stpr.transforms();
241− var len = transforms.length;
225+ var len = transforms.length;
242− for (var i = 0; i < len; ++i) {
226+ for (var i = 0; i < len; ++i) {
243− var m = transforms[i];
227+ var m = transforms[i];
244− ctx.save();
228+ ctx.save();
245− ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
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'));
246 }
240 }
247− } else if (form.form.ctor !== 'FGroup') {
241+ div.removeChild(node);
248− renderForm(function() { update(div, model, model); }, ctx, form);
249 }
242 }
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'));
250 }
248 }
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 };
252}
280}
253
281
282+
254−function update(node, oldModel, newModel) {
283+function update(div, _, model) {
255− if (!node.getContext) {
284+ var w = model.w;
256− return node.parentNode.replaceChild(render(newModel), node);
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+ }
257 }
292 }
258− var ctx = node.getContext('2d');
293+ var stpr = stepper(model.forms);
259− var w = newModel.w, h = newModel.h;
294+ var tracker = updateTracker(w,h,div);
260− ctx.clearRect(-w/2, -h/2, w, h);
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;
261}
311}
262
312
263return { render:render, update:update };
313return { render:render, update:update };
runtime/Render/Element.js+7−7
@@ -3,7 +3,7 @@ ElmRuntime.Render.Element = function() {
3'use strict';
3'use strict';
4
4
5var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
5var 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,
7 addTransform = Utils.addTransform, removeTransform = Utils.removeTransform,
7 addTransform = Utils.addTransform, removeTransform = Utils.removeTransform,
8 fromList = Utils.fromList, eq = Utils.eq;
8 fromList = Utils.fromList, eq = Utils.eq;
9
9
@@ -18,7 +18,7 @@ function setProps(props, e) {
18 if (props.href !== '') {
18 if (props.href !== '') {
19 var a = newElement('a');
19 var a = newElement('a');
20 a.href = props.href;
20 a.href = props.href;
21− addTo(a,e);
21+ a.appendChild(e);
22 return a;
22 return a;
23 }
23 }
24 return e;
24 return e;
@@ -63,7 +63,7 @@ function fittedImage(w, h, src) {
63 };
63 };
64 img.src = src;
64 img.src = src;
65 img.name = src;
65 img.name = src;
66− addTo(e,img);
66+ e.appendChild(img);
67 return e;
67 return e;
68}
68}
69
69
@@ -85,7 +85,7 @@ function croppedImage(elem, w, h, src) {
85 };
85 };
86 img.src = src;
86 img.src = src;
87 img.name = src;
87 img.name = src;
88− addTo(e,img);
88+ e.appendChild(img);
89 return e;
89 return e;
90}
90}
91
91
@@ -95,7 +95,7 @@ function goRight(e) { e.style.styleFloat = e.style.cssFloat = "left"; return e;
95function flowWith(f, array) {
95function flowWith(f, array) {
96 var container = newElement('div');
96 var container = newElement('div');
97 for (var i = array.length; i--; ) {
97 for (var i = array.length; i--; ) {
98− addTo(container, f(render(array[i])));
98+ container.appendChild(f(render(array[i])));
99 }
99 }
100 return container;
100 return container;
101}
101}
@@ -143,7 +143,7 @@ function container(pos,elem) {
143 var div = newElement('div');
143 var div = newElement('div');
144 div.style.position = 'relative';
144 div.style.position = 'relative';
145 div.style.overflow = 'hidden';
145 div.style.overflow = 'hidden';
146− addTo(div,e);
146+ div.appendChild(e);
147 return div;
147 return div;
148}
148}
149
149
@@ -256,7 +256,7 @@ function updateProps(node, curr, next) {
256 if (currP.href === '') {
256 if (currP.href === '') {
257 var a = newElement('a');
257 var a = newElement('a');
258 a.href = props.href;
258 a.href = props.href;
259− addTo(a,e);
259+ a.appendChild(e);
260 e.parentNode.replaceChild(a,e);
260 e.parentNode.replaceChild(a,e);
261 } else {
261 } else {
262 node.parentNode.href = props.href;
262 node.parentNode.href = props.href;