on master help sign in
- Break common functions into Utils files.
4587d3devancz
libraries/Graphics/Element.elm+13−4
@@ -63,7 +63,7 @@ data ElementPrim
63 | Flow Direction [Element]
63 | Flow Direction [Element]
64 | Spacer
64 | Spacer
65 | RawHtml JSString
65 | RawHtml JSString
66− | DomNode JSElement
66+ | Custom -- for custom Elements implemented in JS, see collage for example
67
67
68data ImageStyle = Plain | Fitted | Cropped (Int,Int)
68data ImageStyle = Plain | Fitted | Cropped (Int,Int)
69
69
@@ -94,9 +94,18 @@ flow dir es =
94 DIn -> newFlow (List.maximum ws) (List.maximum hs)
94 DIn -> newFlow (List.maximum ws) (List.maximum hs)
95 DOut -> newFlow (List.maximum ws) (List.maximum hs)
95 DOut -> newFlow (List.maximum ws) (List.maximum hs)
96
96
97+above hi lo =
97−above hi lo = newElement (max (widthOf hi) (widthOf lo)) (heightOf hi + heightOf lo) (Flow DDown [hi,lo])
98+ newElement (max (widthOf hi) (widthOf lo))
99+ (heightOf hi + heightOf lo)
100+ (Flow DDown [hi,lo])
101+below lo hi =
98−below lo hi = newElement (max (widthOf hi) (widthOf lo)) (heightOf hi + heightOf lo) (Flow DDown [hi,lo])
102+ newElement (max (widthOf hi) (widthOf lo))
103+ (heightOf hi + heightOf lo)
104+ (Flow DDown [hi,lo])
105+beside lft rht =
99−beside lft rht = newElement (widthOf lft + widthOf rht) (max (heightOf lft) (heightOf rht)) (Flow right [lft,rht])
106+ newElement (widthOf lft + widthOf rht)
107+ (max (heightOf lft) (heightOf rht))
108+ (Flow right [lft,rht])
100
109
101layers es =
110layers es =
102 let ws = List.map widthOf es
111 let ws = List.map widthOf es
libraries/Native/Graphics/Matrix.js+3−3
@@ -27,10 +27,10 @@ Elm.Native.Graphics.Matrix = function(elm) {
27 return new A([m0, m1, m0*x + m1*y + m[2],
27 return new A([m0, m1, m0*x + m1*y + m[2],
28 m3, m4, m3*x + m4*y + m[5]]);
28 m3, m4, m3*x + m4*y + m[5]]);
29 }
29 }
30− function matrix(a,b,c,d,e,f,m) {
30+ function matrix(n11, n12, n21, n22, dx, dy, m) {
31 var m0 = m[0], m1 = m[1], m3 = m[3], m4 = m[4];
31 var m0 = m[0], m1 = m[1], m3 = m[3], m4 = m[4];
32− return new A([m0*a + m1*d, m0*b + m1*e, m0*c + m1*f + m[2],
32+ return new A([m0*n11 + m1*n12, m0*n21 + m1*n22, m0*dx + m1*dy + m[2],
33− m3*a + m4*d, m3*b + m4*e, m3*c + m4*f + m[5]]);
33+ m3*n11 + m4*n12, m3*n21 + m4*n22, m3*dx + m4*dy + m[5]]);
34 }
34 }
35
35
36 return elm.Native.Graphics.Matrix = {
36 return elm.Native.Graphics.Matrix = {
runtime/Init.js+26−47
@@ -19,9 +19,9 @@ Elm.init = function(module, baseNode) {
19 }
19 }
20
20
21 // ensure that baseNode exists and is properly formatted.
21 // ensure that baseNode exists and is properly formatted.
22− var Render = ElmRuntime.Render.Element;
23 if (typeof baseNode === 'undefined') {
22 if (typeof baseNode === 'undefined') {
23+ var newElement = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
24− baseNode = Render.newElement('div');
24+ baseNode = newElement('div');
25 document.body.appendChild(baseNode);
25 document.body.appendChild(baseNode);
26 baseNode.style.width = window.innerWidth + 'px';
26 baseNode.style.width = window.innerWidth + 'px';
27 baseNode.style.height = window.innerHeight + 'px';
27 baseNode.style.height = window.innerHeight + 'px';
@@ -31,7 +31,7 @@ Elm.init = function(module, baseNode) {
31 baseNode.style.height = window.innerHeight + 'px';
31 baseNode.style.height = window.innerHeight + 'px';
32 }, true);
32 }, true);
33
33
34− var style = Render.newElement('style');
34+ var style = newElement('style');
35 style.type = 'text/css';
35 style.type = 'text/css';
36 style.innerHTML = "html,head,body { padding:0; margin:0; }" +
36 style.innerHTML = "html,head,body { padding:0; margin:0; }" +
37 "body { font-family: calibri, helvetica, arial, sans-serif; }";
37 "body { font-family: calibri, helvetica, arial, sans-serif; }";
@@ -40,38 +40,43 @@ Elm.init = function(module, baseNode) {
40
40
41 // create the actuall RTS. Any impure modules will attach themselves to this
41 // create the actuall RTS. Any impure modules will attach themselves to this
42 // object. This permits many Elm programs to be embedded per document.
42 // object. This permits many Elm programs to be embedded per document.
43− var elm = { notify: notify, node: baseNode, id: ElmRuntime.guid(), inputs: inputs };
43+ var elm = {notify: notify, node: baseNode, id: ElmRuntime.guid(), inputs: inputs};
44
44
45− // evaluate the given module and extract its 'main' value.
45+ // If graphics are enabled, set up the `main` value in baseNode.
46− signalGraph = module(elm).main;
46+ if (baseNode !== null) {
47+ var Render = ElmRuntime.use(ElmRuntime.Render.Element);
47
48
48− // make sure the signal graph is actually a signal, extract the visual model,
49+ // evaluate the given module and extract its 'main' value.
49− // and filter out any unused inputs.
50+ signalGraph = module(elm).main;
50− var Signal = Elm.Signal(elm);
51− if (!('recv' in signalGraph)) signalGraph = Signal.constant(signalGraph);
52− visualModel = signalGraph.value;
53− inputs = ElmRuntime.filterDeadInputs(inputs);
54
51
55− // Add the visualModel to the DOM
52+ // make sure the signal graph is actually a signal, extract the visual model,
56− baseNode.appendChild(Render.render(visualModel));
53+ // and filter out any unused inputs.
54+ var Signal = Elm.Signal(elm);
55+ if (!('recv' in signalGraph)) signalGraph = Signal.constant(signalGraph);
56+ visualModel = signalGraph.value;
57+ inputs = ElmRuntime.filterDeadInputs(inputs);
57
58
59+ // Add the visualModel to the DOM
60+ baseNode.appendChild(Render.render(visualModel));
61+
58− if ('Window' in elm) {
62+ if ('Window' in elm) {
59 var w = baseNode.clientWidth;
63 var w = baseNode.clientWidth;
60 if (w !== elm.Window.dimensions.value._0) {
64 if (w !== elm.Window.dimensions.value._0) {
61 notify(elm.Window.dimensions.id,
65 notify(elm.Window.dimensions.id,
62 Elm.Native.Utils(elm).Tuple2(w, baseNode.clientHeight));
66 Elm.Native.Utils(elm).Tuple2(w, baseNode.clientHeight));
63 }
67 }
64− }
68+ }
65
69
66− // set up updates so that the DOM is adjusted as necessary.
70+ // set up updates so that the DOM is adjusted as necessary.
67− var update = Render.update;
71+ var update = Render.update;
68− function domUpdate(value) {
72+ function domUpdate(value) {
69 update(baseNode.firstChild, visualModel, value);
73 update(baseNode.firstChild, visualModel, value);
70 visualModel = value;
74 visualModel = value;
71 return value;
75 return value;
72− }
76+ }
73
77
74− signalGraph = A2(Signal.lift, domUpdate, signalGraph);
78+ signalGraph = A2(Signal.lift, domUpdate, signalGraph);
79+ }
75
80
76 function send(name, value) {
81 function send(name, value) {
77 var e = document.createEvent('Event');
82 var e = document.createEvent('Event');
@@ -85,29 +90,3 @@ Elm.init = function(module, baseNode) {
85
90
86 return { send : send, recv : recv };
91 return { send : send, recv : recv };
87};
92};
88−
89−// Helper function to filter dead inputs. Not specific to initialization.
90−ElmRuntime = ElmRuntime || {};
91−ElmRuntime.counter = 0;
92−ElmRuntime.guid = function() { ++ElmRuntime.counter; return ElmRuntime.counter; }
93−ElmRuntime.filterDeadInputs = function() {
94− 'use strict';
95− function isAlive(input) {
96− if (!('defaultNumberOfKids' in input)) return true;
97− var len = input.kids.length;
98− if (len == 0) return false;
99− if (len > input.defaultNumberOfKids) return true;
100− var alive = false;
101− for (var i = len; i--; ) {
102− alive = alive || isAlive(input.kids[i]);
103− }
104− return alive;
105− }
106− return function filterDeadInputs(inputs) {
107− var temp = [];
108− for (var i = inputs.length; i--; ) {
109− if (isAlive(inputs[i])) temp.push(inputs[i]);
110− }
111− return temp;
112− };
113−}();
runtime/Render/Collage.js+50−57
@@ -1,45 +1,24 @@
1
1
2−ElmRuntime.Render.Collage = function(rts) {
2+ElmRuntime.Render.Collage = function() {
3− /*
3+'use strict';
4−var JS = Elm.JavaScript;
5
4
5+var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
6+var newElement = Utils.newElement, addTo = Utils.addTo, extract = Utils.extract;
7+
6−function tracePoints(ctx,points) {
8+function trace(ctx, path) {
7 var i = points.length - 1;
9 var i = points.length - 1;
8 if (i <= 0) return;
10 if (i <= 0) return;
9− ctx.moveTo(points[i][1], points[i][2]);
11+ ctx.moveTo(points[i]._0, points[i]._1);
10− while (i--) { ctx.lineTo(points[i][1], points[i][2]); }
12+ while (i--) { ctx.lineTo(points[i]._0, points[i]._1); }
11}
13}
12
14
13−function solid(ctx,color,points) {
15+function line(ctx,style,path) {
14− tracePoints(ctx,points);
16+ var isSolid = style.dashing.ctor === 'Nil';
15− ctx.strokeStyle = Elm.Color.extract(color);
17+ isSolid ? trace(ctx, path) : customLineHelp(ctx, style, path);
16 ctx.stroke();
18 ctx.stroke();
17−};
18−
19−function filled(ctx,color,points) {
20− tracePoints(ctx,points);
21− ctx.fillStyle = Elm.Color.extract(color);
22− ctx.fill();
23}
19}
24
20
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) {
21+function customLineHelp(ctx, pattern, points) {
43 var i = points.length - 1;
22 var i = points.length - 1;
44 if (i <= 0) return;
23 if (i <= 0) return;
45 var x0 = points[i][1], y0 = points[i][2];
24 var x0 = points[i][1], y0 = points[i][2];
@@ -69,17 +48,32 @@ var customLineHelp = function(ctx, pattern, points) {
69 }
48 }
70 x0 = x1; y0 = y1;
49 x0 = x1; y0 = y1;
71 }
50 }
72−};
51+}
73
52
74−function drawLine(ctx,form) {
53+function drawLine(ctx, style, path) {
75− var points = form[3][1];
54+ ctx.lineWidth = style.width;
76− switch(form[1][0]) {
55+ ctx.lineCap = style.cap.ctor.toLowerCase();
77− case "Solid" : return solid(ctx,form[2],points);
56+ ctx.lineJoin = style.join.ctor.toLowerCase();
78− case "Dotted": return customLine([3,3],ctx,form[2],points);
57+ ctx.miterLimit = style.miterLimit;
79− case "Dashed": return customLine([8,4],ctx,form[2],points);
58+ ctx.strokeStyle = extract(style.color);
80− case "Custom": return customLine(form[1][1],ctx,form[2],points);
59+ return line(ctx, style, path);
81− }
60+}
61+
62+function filled(ctx,color,points) {
63+ tracePoints(ctx,points);
64+ ctx.fillStyle = extract(color);
65+ ctx.fill();
66+}
67+
68+function textured(redo,ctx,src,points) {
69+ var img = new Image();
70+ img.src = JS.castStringToJSString(src);
71+ img.onload = redo;
72+
73+ tracePoints(ctx,points);
74+ ctx.fillStyle = ctx.createPattern(img,'repeat');
75+ ctx.fill();
82−};
76+}
83
77
84function drawShape(redo,ctx,shapeStyle,color,points) {
78function drawShape(redo,ctx,shapeStyle,color,points) {
85 switch(shapeStyle[0]) {
79 switch(shapeStyle[0]) {
@@ -98,25 +92,24 @@ function drawImage(redo,ctx,w,h,src) {
98 ctx.drawImage(img,-w/2,-h/2,w,h);
92 ctx.drawImage(img,-w/2,-h/2,w,h);
99}
93}
100
94
101−function renderForm(redo,ctx,theta,scale,x,y,form) {
95+function renderForm(redo,ctx,form) {
102 ctx.save();
96 ctx.save();
103− if (x !== 0 || y !== 0) ctx.translate(x,y);
97+ var m = form.transform;
104− if (theta !== ~~theta) ctx.rotate(2*Math.PI*theta);
98+ ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
105− if (scale !== 1) ctx.scale(scale,scale);
106 ctx.beginPath();
99 ctx.beginPath();
107− switch(form[0]) {
100+ switch(form.form.ctor) {
108− case "FLine": drawLine(ctx,form); break;
101+ case 'FPath' : drawLine(ctx, form._0, form._1); break;
109− case "FShape": drawShape(redo,ctx,form[1],form[2],form[3][1]); break;
102+ case 'FShape': drawShape(redo, ctx, form._0, form._1); break;
110− case "FImage": drawImage(redo,ctx,form[1],form[2],form[3]); break;
103+ case 'FImage': drawImage(redo, ctx, form._0, form._1, form._2, form._3); break;
104+ case 'FGroup': renderForms(redo, ctx, form.form._0); break;
111 }
105 }
112 ctx.restore();
106 ctx.restore();
113−};
107+}
114
108
115−function renderForms(redo,ctx,w,h,forms) {
109+function renderForms(redo, ctx, forms) {
116− ctx.clearRect(0,0,w,h);
110+ forms = toArray(forms);
117 for (var i = forms.length; i--; ) {
111 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]);
112+ renderForm(redo,ctx,forms[i]);
120 }
113 }
121}
114}
122
115
@@ -313,5 +306,5 @@ function insideShape(point,theta,scale,pos,points) {
313}
306}
314
307
315return {collage:collage, updateCollage:updateCollage, insideForm:insideForm};
308return {collage:collage, updateCollage:updateCollage, insideForm:insideForm};
316− */
309+
317};
310};
runtime/Render/Element.js+4−25
@@ -2,24 +2,8 @@
2ElmRuntime.Render.Element = function() {
2ElmRuntime.Render.Element = function() {
3'use strict';
3'use strict';
4
4
5−var fromList = Elm.JavaScript({}).fromList;
5+var Utils = use(ElmRuntime.Render.Utils);
6−var eq = Elm.Native.Utils({}).eq;
6+var newElement = Utils.newElement, addTo = Utils.addTo, extract = Utils.extract;
7−
8−function newElement(elementType) {
9− var e = document.createElement(elementType);
10− e.style.padding = "0";
11− e.style.margin = "0";
12− return e;
13−}
14−
15−function addTo(container, elem) {
16− container.appendChild(elem);
17−}
18−
19−function extract(c) {
20− if (c._3 === 1) { return 'rgb(' + c._0 + ',' + c._1 + ',' + c._2 + ')'; }
21− return 'rgba(' + c._0 + ',' + c._1 + ',' + c._2 + ',' + c._3 + ')';
22−}
23
7
24function setProps(props, e) {
8function setProps(props, e) {
25 e.style.width = (props.width |0) + 'px';
9 e.style.width = (props.width |0) + 'px';
@@ -279,11 +263,6 @@ function update(node, curr, next) {
279 }
263 }
280}
264}
281
265
282−return {
283− render:render,
266+return { render:render, update:update };
284− update:update,
285− addTo:addTo,
286− newElement:newElement
287−};
288
267
289−}();
268+};
runtime/Render/Utils.jsnew file+30
@@ -0,0 +1,30 @@
1+
2+ElmRuntime.Render.Utils = function() {
3+'use strict';
4+
5+function newElement(elementType) {
6+ var e = document.createElement(elementType);
7+ e.style.padding = "0";
8+ e.style.margin = "0";
9+ return e;
10+}
11+
12+function addTo(container, elem) {
13+ container.appendChild(elem);
14+}
15+
16+function extract(c) {
17+ if (c._3 === 1) { return 'rgb(' + c._0 + ',' + c._1 + ',' + c._2 + ')'; }
18+ return 'rgba(' + c._0 + ',' + c._1 + ',' + c._2 + ',' + c._3 + ')';
19+}
20+
21+var fromList = Elm.JavaScript({}).fromList;
22+var eq = Elm.Native.Utils({}).eq;
23+
24+return {addTo:addTo,
25+ newElement:newElement,
26+ extract:extract,
27+ fromList:fromList,
28+ eq:eq
29+ };
30+};
runtime/Utils.jsnew file+33
@@ -0,0 +1,33 @@
1+
2+(function() {
3+'use strict';
4+
5+ElmRuntime.counter = 0;
6+ElmRuntime.guid = function() { return ElmRuntime.counter++; }
7+
8+ElmRuntime.use = function(M) {
9+ if (typeof M === 'function') M = M();
10+ return M;
11+};
12+
13+function isAlive(input) {
14+ if (!('defaultNumberOfKids' in input)) return true;
15+ var len = input.kids.length;
16+ if (len == 0) return false;
17+ if (len > input.defaultNumberOfKids) return true;
18+ var alive = false;
19+ for (var i = len; i--; ) {
20+ alive = alive || isAlive(input.kids[i]);
21+ }
22+ return alive;
23+}
24+
25+ElmRuntime.filterDeadInputs = function(inputs) {
26+ var temp = [];
27+ for (var i = inputs.length; i--; ) {
28+ if (isAlive(inputs[i])) temp.push(inputs[i]);
29+ }
30+ return temp;
31+};
32+
33+}());