/* TransformFunction support for ASVDrawing v0.1 Peter Hall 2003 www.peterjoel.com myASVDrawing.setTransformFunction(function) myASVDrawing.removeTransform() Static methods: ASVDrawing.createWhirl ASVDrawing.createPinch ASVDrawing.createWaves ASVDrawing.createFreeform Supply a function as the argument to setTransformFunction. It allows custom, non-linear transformations to be applied to a drawing. The function argument should take two arguments, which are xa nd y coordinates. It should return an object with x and y values, corresponding to the transformed coordinates. The following function returns the points unchanged, so has no effect: function doNothing(x,y){ return {x:x, y:y}; } myDrawing.setTransformFunction(doNothing); The static methods, ASVDrawing.createWhirl and ASVDrawing.createPinch, return ready-made transform functions, based on the parameters. */ // this accepts a function as an argument, which can be used to transform a point // a transformation function takes two args (x,y) and returns an object with x and y properties // Use this method to apply non-linear transformation. ASVDrawing.prototype.setTransformFunction = function (transformFunc){ if(typeof transformFunc != "function"){ this.removeTransform(); }else{ this.M = function(x,y){ this.tfMoveTo(x,y,transformFunc); } this.L = function(x,y){ this.tfLineTo(x,y,transformFunc); } this.C = function(cx,cy,ax,ay){ this.tfCurveTo(cx,cy,ax,ay,transformFunc); } } } ASVDrawing.prototype.removeTransform = function(){ this.M = moveTo; this.L = lineTo; this.C = curveTo; } // Some MovieClip methods, used for applying non-linear transforms. MovieClip.prototype.tfMoveTo = function (x,y,func){ var p = func(x,y); this.moveTo(p.x,p.y); } MovieClip.prototype.tfLineTo = function (x,y,func){ var p = func(x,y); this.lineTo(p.x,p.y); } MovieClip.prototype.tfCurveTo = function (cx,cy,ax,ay,func){ var cp = func(cx,cy); var ap = func(ax,ay); this.curveTo(cp.x, cp.y, ap.x, ap.y); } /* The following static methods return a function, which can be passed to setTransformFunction */ // centreX,centreY,radius define a circle in which the transform will occur // amount is an angle in degrees; how much the image will be distorted ASVDrawing.createWhirl = function (centreX, centreY, radius, amount){ // prepare variables so they don't need to be recalculated each invokation var radius2 = radius*radius; var rotate = amount*Math.PI/180; return function (x,y){ var x2 = x-centreX; var y2 = y-centreY; var r2 = x2*x2+y2*y2; // confine to a circlular area. Outside of that, leave points unchanged. if(r2>radius2)return {x:x,y:y}; var th = Math.cos(Math.PI/2 + Math.PI*Math.sqrt(r2)/radius)*rotate; var cosTh = Math.cos(th); var sinTh = Math.sin(th); return {x:x2*cosTh+y2*sinTh+centreX, y:y2*cosTh-x2*sinTh+centreY}; } } // xMin,yMin,xMax,yMax is bounding box of transform area // xAmount,yAmount are percentages of width or height resp. // Positive values "pinch" and negative values "inflate" ASVDrawing.createPinch = function (xMin, yMin, xMax, yMax, xAmount, yAmount){ // prepare variables so they don't need to be recalculated each invokation var w = xMax-xMin; var h = yMax-yMin; var h2 = h/2; var w2 = w/2; var ax = xAmount*w/200; var ay = yAmount*h/200; return function(x,y){ // return unchanged if point is outside the rectangle if(xxMax || yyMax) return {x:x,y:y}; if(xAmount){ var y2 = (y-yMin)/h2-1; var gx = (1-y2*y2)*ax; var newX = xMin+gx+(x-xMin)*(w-2*gx)/w; }else{ var newX = x; } if(yAmount){ var x2 = (x-xMin)/w2-1; var gy = (1-x2*x2)*ay; var newY = yMin+gy+(y-yMin)*(h-2*gy)/h; }else{ var newY = y; } return {x:newX, y:newY}; } } // xMin,yMin,xMax,yMax is bounding box of transform area // xAmount,yAmount are percentages of width or height resp. // xCount, yCount are the number of waves in each direction // offsets determine where the waves begin as an angle in degrees ASVDrawing.createWaves = function (xMin, yMin, xMax, yMax, xAmount, yAmount, xCount, yCount, xOffset, yOffset){ // prepare variables so they don't need to be recalculated each invokation var w = xMax-xMin; var h = yMax-yMin; var jx = Math.PI*xCount/h; var jy = Math.PI*yCount/w; xOffset = xOffset*Math.PI/180; yOffset = yOffset*Math.PI/180; return function(x,y){ // return unchanged if point is outside the rectangle if(xxMax || yyMax) return {x:x,y:y}; var newX = xAmount ? x+xAmount*Math.sin(jx*y+xOffset) : x; var newY = yAmount ? y+yAmount*Math.sin(jy*x+yOffset) : y; return {x:newX, y:newY}; } } // xMin,..yMax are the top lef and bottom right corners of original rectangle. // x0,..y3 are all four corners of transformed rectangle, starting at xMin,yMin and // working clockwise to x3,y3 ASVDrawing.createFreeform = function(xMin, yMin, xMax, yMax, x0,y0,x1,y1,x2,y2,x3,y3){ var w = xMax - xMin; var h = yMax - yMin; var w2_0 = x1-x0; var w2_1 = x2-x3; var h2_0 = y1-y0; var h2_1 = y2-y3; return function(x,y){ var gx = (x-xMin)/w; var gy = (y-yMin)/h; var bx = x0 + gy*(x3-x0); var by = y0 + gy*(y3-y0); return {x: bx + gx*((x1+gy*(x2-x1))-bx), y: by + gx*((y1+gy*(y2-y1))-by)}; } }