elm/core-js/Graphics/Collage.js

214 lines
6.6 KiB
JavaScript
Raw Normal View History

2012-08-31 06:42:33 +00:00
var Collage = function() {
function tracePoints(ctx,points) {
var i = points.length - 1;
if (i <= 0) return;
ctx.moveTo(points[i][1], points[i][2]);
while (i--) { ctx.lineTo(points[i][1], points[i][2]); }
}
function solid(ctx,color,points) {
tracePoints(ctx,points);
ctx.strokeStyle = ElmCode.Graphics.Color.extract(color);
ctx.stroke();
};
function filled(ctx,color,points) {
tracePoints(ctx,points);
ctx.fillStyle = ElmCode.Graphics.Color.extract(color);
ctx.fill();
}
function textured(redo,ctx,src,points) {
var img = new Image();
img.src = Foreign.JavaScript.castStringToJSString(src);
img.onload = redo;
tracePoints(ctx,points);
ctx.fillStyle = ctx.createPattern(img,'repeat');
ctx.fill();
}
function customLine(pattern,ctx,color,points) {
if (pattern.length === 0) { pattern = [8,4]; }
customLineHelp(ctx, pattern, points);
ctx.strokeStyle = ElmCode.Graphics.Color.extract(color);
ctx.stroke();
};
var customLineHelp = function(ctx, pattern, points) {
var i = points.length - 1;
if (i <= 0) return;
var x0 = points[i][1], y0 = points[i][2];
var x1=0, y1=0, dx=0, dy=0, remaining=0, nx=0, ny=0;
var pindex = 0, plen = pattern.length;
var draw = true, segmentLength = pattern[0];
ctx.moveTo(x0,y0);
while (i--) {
x1 = points[i][1]; y1 = points[i][2];
dx = x1 - x0; dy = y1 - y0;
remaining = Math.sqrt(dx * dx + dy * dy);
while (segmentLength <= remaining) {
x0 += dx * segmentLength / remaining;
y0 += dy * segmentLength / remaining;
ctx[draw ? 'lineTo' : 'moveTo'](x0, y0);
// update starting position
dx = x1 - x0; dy = y1 - y0;
remaining = Math.sqrt(dx * dx + dy * dy);
// update pattern
draw = !draw;
pindex = (pindex + 1) % plen;
segmentLength = pattern[pindex];
}
if (remaining > 0) {
ctx[draw ? 'lineTo' : 'moveTo'](x1, y1);
segmentLength -= remaining;
}
x0 = x1; y0 = y1;
}
};
function drawLine(ctx,form) {
var points = Foreign.JavaScript.castListToJSArray(form[3][1]);
switch(form[1][0]) {
case "Solid" : return solid(ctx,form[2],points);
case "Dotted": return customLine([3,3],ctx,form[2],points);
case "Dashed": return customLine([8,4],ctx,form[2],points);
case "Custom":
var pattern = Foreign.JavaScript.castListToJSArray(form[1][1]);
customLine(pattern,ctx,form[2],points);
}
};
function drawShape(redo,ctx,shapeStyle,color,points) {
points = Foreign.JavaScript.castListToJSArray(points);
if (points.length > 0) points.push(points[0]);
switch(shapeStyle[0]) {
case "Filled": return filled(ctx,color,points);
case "Outlined": return solid(ctx,color,points);
case "Textured": return textured(redo,ctx,shapeStyle[1],points);
case "CustomOutline":
var pattern = Foreign.JavaScript.castListToJSArray(shapeStyle[1]);
customLine(pattern,ctx,color,points);
}
};
function drawImage(redo,ctx,w,h,src) {
var img = new Image();
img.onload = redo;
img.src = Foreign.JavaScript.castStringToJSString(src);
ctx.drawImage(img,-w/2,-h/2,w,h);
}
function renderForm(redo,ctx,theta,scale,x,y,form) {
ctx.save();
if (x !== 0 || y !== 0) ctx.translate(x,y);
if (theta !== ~~theta) ctx.rotate(2*Math.PI*theta);
if (scale !== 1) ctx.scale(scale,scale);
2012-08-31 06:42:33 +00:00
ctx.beginPath();
switch(form[0]) {
case "FLine": drawLine(ctx,form); break;
case "FShape": drawShape(redo,ctx,form[1],form[2],form[3][1]); break;
case "FImage": drawImage(redo,ctx,form[1],form[2],form[3]); break;
}
ctx.restore();
};
function renderForms(redo,ctx,w,h,forms) {
ctx.clearRect(0,0,w,h);
for (var i = forms.length; i--; ) {
var f = forms[i];
renderForm(redo,ctx,f[1],f[2],f[3][1],f[3][2],f[4]);
}
}
function collageForms(w,h,forms) {
var canvas = Render.newElement('canvas');
canvas.style.width = (~~w) + 'px';
canvas.style.height = (~~h) + 'px';
canvas.style.display = "block";
2012-08-31 06:42:33 +00:00
canvas.width = ~~w;
canvas.height = ~~h;
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
var w = canvas.width, h = canvas.height;
function redo() { renderForms(this,ctx,w,h,forms); }
renderForms(redo,ctx,w,h,forms);
return canvas;
}
canvas.innerHTML = "Your browser does not support the canvas element.";
return canvas;
2012-08-31 06:42:33 +00:00
};
function collageElement(w,h,theta,scale,x,y,elem) {
var e = Render.render(elem);
var t = "translate(" + (x - elem[3] / 2) + "px,"+ (y - elem[4] / 2) + "px)";
var r = theta === (~~theta) ? "" : "rotate(" + theta*360 + "deg)";
var s = scale === 1 ? "" : "scale(" + scale + "," + scale + ")";
var transforms = t + " " + s + " " + r;
e.style.transform = transforms;
e.style.msTransform = transforms;
e.style.MozTransform = transforms;
e.style.webkitTransform = transforms;
e.style.OTransform = transforms;
2012-08-31 06:42:33 +00:00
var div = Render.newElement('div');
Render.addTo(div,e);
div.style.width = (~~w) + "px";
div.style.height = (~~h) + "px";
div.style.overflow = "hidden";
2012-08-31 06:42:33 +00:00
return div;
}
function collage(w,h,formss) {
if (formss.length === 0) { return collageForms(w,h,[]); }
var elems = new Array(formss.length);
for (var i = formss.length; i--; ) {
var f = formss[i];
if (typeof f[0] === "string") {
elems[i] = collageElement(w,h,f[1],f[2],f[3][1],f[3][2],f[4][1]);
} else {
elems[i] = collageForms(w,h,f);
}
}
if (formss.length === 1) { return elems[0]; }
return Render.flowWith(Render.goIn,function(x){return x},elems);
}
function updateFormSet(node,currSet,nextSet) {
if (Value.eq(nextSet,currSet)) return;
var w = node.style.width.slice(0,-2) - 0;
var h = node.style.height.slice(0,-2) - 0;
if (typeof nextSet[0] === "object") {
if (typeof currSet[0] === "object") {
if (node.getContext) {
var ctx = node.getContext('2d');
function redo() { renderForms(this,ctx,w,h,nextSet); }
return renderForms(redo,ctx,w,h,nextSet);
}
}
var newNode = collageForms(w,h,nextSet);
newNode.style.position = 'absolute';
return node.parentNode.replaceChild(newNode,node);
}
var f = nextSet;
var newNode = collageElement(w,h,f[1],f[2],f[3][1],f[3][2],f[4][1]);
newNode.style.position = 'absolute';
return node.parentNode.replaceChild(newNode,node);
}
// assumes that the form sets are the same length.
2012-08-31 06:42:33 +00:00
function updateCollage(node,currs,nexts) {
if (nexts.length === 1) {
return updateFormSet(node,currs[0],nexts[0]);
}
var kids = node.childNodes;
var len = kids.length;
for (var i = len; i--; ) {
updateFormSet(kids[len-i-1], currs[i], nexts[i]);
}
}
return {collage:collage, updateCollage:updateCollage};
}();