function Highlight(CTRL){ //CTRL.style.color = ButtonLight; } function DeHighlight(CTRL){ //CTRL.style.color = ButtonBorder; } // Attach load event xAttachEventOnLoad("load", cornerInt); function cornerInt(){ // Get all DIV elements var divElements = document.getElementsByTagName("DIV"); var divCount = divElements.length; var t = 0; objsArray = new Array(); // Loop through all DIVs for(var i = 0; i < divCount; i++){ var currentDiv = divElements[i]; if(radius = currentDiv.getAttribute("radius")){ if(!(corners = currentDiv.getAttribute("corners"))) corners = "TR,TL,BR,BL"; var newObj = new curvyCorners(currentDiv, radius, corners); objsArray[t] = newObj; t++; } } //alert(objsArray); var arrayLength = objsArray.length; for(var x = 0; x < arrayLength; x++){ objsArray[x].doCorners(); } } // ------------- curvyCorners OBJECT function curvyCorners(boxObj, radiusInt, cornersCSVStr) { // Set objects properties this.box = boxObj; this.radius = (Math.round(parseInt(radiusInt)/2))*2; this.corners = cornersCSVStr.split(","); // Array // Setup global variables this.masterCorner = null; this.masterCornerType = null; this.cornersAvailable = new Array("TR", "TL", "BR", "BL"); // Get box formatting details and set properties this.boxHeight = parseInt(((this.box.style.height != "")? this.box.style.height.substring(0, this.box.style.height.indexOf("px")) : this.box.scrollHeight)); this.boxWidth = parseInt(((this.box.style.width != "")? this.box.style.width.substring(0, this.box.style.width.indexOf("px")) : this.box.scrollWidth)); this.borderWidth = parseInt(((this.box.style.borderWidth != "")? this.box.style.borderWidth.slice(0, this.box.style.borderWidth.indexOf("px")) : 0)); this.boxColour = ((this.box.style.backgroundColor.substr(0, 3) == "rgb")? rgb2Hex(this.box.style.backgroundColor) : this.box.style.backgroundColor); this.borderColour = ((this.box.style.borderColor != "" && this.borderWidth > 0)? ((this.box.style.borderColor.substr(0, 3) == "rgb")? rgb2Hex(this.box.style.borderColor) : this.box.style.borderColor) : this.boxColour); this.borderRadius = parseInt(this.radius - this.borderWidth); this.borderString = this.borderWidth + "px" + " solid " + this.borderColour; this.posStart = (0 - this.radius); this.posAdjust = (Math.floor(Math.sqrt(Math.pow((this.radius - this.borderWidth),2)/2))); // Make box relative if not already absolute if(this.box.style.position != "absolute") this.box.style.position = "relative"; // Builds the corners this.doCorners = function() { // Loop once for each corner specfied for(var i in this.cornersAvailable) { // Get current corner type from array var currentCorner = this.cornersAvailable[i]; if(inArray(this.corners, currentCorner) === false) { // No corner is to be rounded so we generated a square to fill the gap var newCorner = document.createElement("DIV"); // Setup corners properties newCorner.style.height = this.radius - this.borderWidth + "px"; newCorner.style.width = this.radius - this.borderWidth + "px"; newCorner.style.position = "absolute"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; newCorner.style.backgroundColor = this.boxColour; switch(currentCorner) { case "TL": newCorner.style.borderLeft = this.borderString; newCorner.style.borderTop = this.borderString; break; case "TR": newCorner.style.borderRight = this.borderString; newCorner.style.borderTop = this.borderString; break; case "BL": newCorner.style.borderLeft = this.borderString; newCorner.style.borderBottom = this.borderString; break; case "BR": newCorner.style.borderRight = this.borderString; newCorner.style.borderBottom = this.borderString; break; } } else{ /* To increase performace we only ever generate one corner. This corner is the bottom right corner. If more that one corner is requested then the other corners will be a cloned version of the first corner. */ if(this.masterCorner != null) { // Create clone of the master corner var newCorner = this.masterCorner.cloneNode(true); } else { // First time round so generate the master corner var newCorner = document.createElement("DIV"); // Setup corners properties newCorner.style.height = this.radius + "px"; newCorner.style.width = this.radius + "px"; newCorner.style.position = "absolute"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; // Cycle the x-axis for(var intx = 0; intx < this.radius; intx++) { // Calculate the value of y1 which identifies the pixels inside the border if((intx +1) >= this.borderRadius) var y1 = -1; else var y1 = (Math.floor(Math.sqrt(Math.pow(this.borderRadius, 2) - Math.pow((intx+1), 2))) - 1); // Only calculate y2 and y3 if there is a border defined if(this.borderRadius != this.radius) { if((intx) >= this.borderRadius) var y2 = -1; else var y2 = Math.ceil(Math.sqrt(Math.pow(this.borderRadius,2) - Math.pow(intx, 2))); if((intx+1) >= this.radius) var y3 = -1; else var y3 = (Math.floor(Math.sqrt(Math.pow(this.radius,2) - Math.pow((intx+1), 2))) - 1); } // Calculate y4 if((intx) >= this.radius) var y4 = -1; else var y4 = Math.ceil(Math.sqrt(Math.pow(this.radius,2) - Math.pow(intx, 2))); // Draw bar on inside of the border with foreground colour if(y1 > -1) this.drawPixel(intx, 0, this.boxColour, 100, (y1+1), newCorner); // Only draw border/foreground antialiased pixels and border if there is a border defined if(this.borderRadius != this.radius) { // Cycle the y-axis for(var inty = (y1 + 1); inty < y2; inty++) { // For each of the pixels that need anti aliasing between the foreground and border colour draw single pixel divs var pixelcolour = BlendColour(this.boxColour, this.borderColour, pixelFraction(intx, inty, this.borderRadius)); this.drawPixel(intx, inty, pixelcolour, 100, 1, newCorner); } // Draw bar for the border if(y3 >= y2) { if (y1 == -1) y1 = 0; this.drawPixel(intx, y2, this.borderColour, 100, (y3 - y2 + 1), newCorner); } // Set the colour for the outside curve var outsideColour = this.borderColour; } else { // Set the coour for the outside curve var outsideColour = this.boxColour; var y3 = y1; } // Cycle the y-axis and draw the anti aliased pixels on the outside of the curve for(var inty = (y3 + 1); inty < y4; inty++) { // For each of the pixels that need anti aliasing between the foreground/border colour & background draw single pixel divs this.drawPixel(intx, inty, outsideColour, (pixelFraction(intx, inty ,this.radius) * 100), 1, newCorner); } } // Store corner as master corner this.masterCorner = newCorner.cloneNode(true); this.masterCornerType = "BR"; } } /* Now we have a new corner we need to reposition all the pixels unless the current corner is the bottom right/ */ if(currentCorner != "BR") { // Loop through all children (pixel bars) var pixelCount = newCorner.childNodes.length; for(var t = 0; t < pixelCount; t++) { // Get current pixel bar var pixelBar = newCorner.childNodes[t]; // Get current top and left properties var pixelBarTop = parseInt(pixelBar.style.top.substring(0, pixelBar.style.top.indexOf("px"))); var pixelBarLeft = parseInt(pixelBar.style.left.substring(0, pixelBar.style.left.indexOf("px"))); var pixelBarHeight = parseInt(pixelBar.style.height.substring(0, pixelBar.style.height.indexOf("px"))); // Reposition pixels if(currentCorner == "TL" || currentCorner == "BL"){ pixelBar.style.left = this.radius -pixelBarLeft -1 + "px"; // Left } if(currentCorner == "TR" || currentCorner == "TL"){ pixelBar.style.top = this.radius -pixelBarHeight -pixelBarTop + "px"; // Top } } } // Position the container switch(currentCorner) { case "TL": newCorner.style.top = (this.posStart + this.posAdjust) + "px"; newCorner.style.left = (this.posStart + this.posAdjust) + "px"; break; case "TR": newCorner.style.top = (this.posStart + this.posAdjust) + "px"; newCorner.style.left = (this.boxWidth - this.posAdjust) + "px"; break; case "BL": newCorner.style.top = (this.boxHeight - this.posAdjust) + "px"; newCorner.style.left = (this.posStart + this.posAdjust) + "px"; break; case "BR": newCorner.style.top = (this.boxHeight - this.posAdjust)+ "px"; newCorner.style.left = (this.boxWidth - this.posAdjust)+ "px"; break; } // Append new corner this.box.appendChild(newCorner); /* We have now drawn all the corner required so we now need to put on the finishing touches. */ // Draw bars ---------------------------------------------- // Turn off current borders this.box.style.borderWidth = "0px"; for(var s = 0; s < 4; s++) { // Create bar var bar = document.createElement("DIV"); // Set the bars properties bar.style.height = this.boxHeight + "px"; //bar.style.height = "6px"; bar.style.width = this.boxWidth + "px"; bar.style.position = "absolute"; bar.style.fontSize = "1px"; bar.style.overflow = "hidden"; bar.style.backgroundColor = this.boxColour; //bar.style.backgroundColor = "#663322"; switch(s) { // Left case 0: bar.style.top = this.posAdjust + "px"; bar.style.left = (this.posStart + this.posAdjust) + "px"; bar.style.width = ((this.radius - this.posAdjust - this.borderWidth) * 2) + "px"; bar.style.height = (this.boxHeight - (2 * this.posAdjust)) + "px"; bar.style.borderLeft = this.borderString; break; // Right case 1: bar.style.top = this.posAdjust + "px"; bar.style.right = (this.posStart + this.posAdjust) + "px"; bar.style.width = ((this.radius - this.posAdjust - this.borderWidth) * 2) + "px"; bar.style.height = (this.boxHeight - (2 * this.posAdjust)) + "px"; bar.style.borderRight = this.borderString; break; // Top case 2: bar.style.top = (this.posStart + this.posAdjust) + "px"; bar.style.left = this.posAdjust + "px"; bar.style.height = ((this.radius - this.posAdjust - this.borderWidth) *2) + "px"; //bar.style.height = "6px"; bar.style.width = (this.boxWidth - (2 * this.posAdjust)) + "px"; bar.style.borderTop = this.borderString; break; // Bottom case 3: bar.style.bottom = (this.posStart + this.posAdjust) + "px"; bar.style.left = this.posAdjust + "px"; bar.style.height = ((this.radius - this.posAdjust - this.borderWidth) * 2) + "px"; bar.style.width = (this.boxWidth - (2 * this.posAdjust)) + "px"; bar.style.borderBottom = this.borderString; break; } // Append bar this.box.appendChild(bar); } } } this.drawPixel = function(intx, inty, colour, transAmount, height, newCorner) { // Create pixel var pixel = document.createElement("DIV"); pixel.style.height = height + "px"; pixel.style.width = "1px"; pixel.style.position = "absolute"; pixel.style.fontSize = "1px"; pixel.style.overflow = "hidden"; pixel.style.backgroundColor = colour; // Set opacity if the transparency is anything other than 100 if (transAmount != 100) setOpacity(pixel, transAmount); // Set the pixels position pixel.style.top = inty + "px"; pixel.style.left = intx + "px"; newCorner.appendChild(pixel); } } // ------------- UTILITY FUNCTIONS /* Blends the two colours by the fraction returns the resulting colour as a string in the format "#FFFFFF" */ function BlendColour(Col1, Col2, Col1Fraction) { var red1 = parseInt(Col1.substr(1,2),16); var green1 = parseInt(Col1.substr(3,2),16); var blue1 = parseInt(Col1.substr(5,2),16); var red2 = parseInt(Col2.substr(1,2),16); var green2 = parseInt(Col2.substr(3,2),16); var blue2 = parseInt(Col2.substr(5,2),16); if(Col1Fraction > 1 || Col1Fraction < 0) Col1Fraction = 1; var endRed = Math.round((red1 * Col1Fraction) + (red2 * (1 - Col1Fraction))); if(endRed > 255) endRed = 255; if(endRed < 0) endRed = 0; var endGreen = Math.round((green1 * Col1Fraction) + (green2 * (1 - Col1Fraction))); if(endGreen > 255) endGreen = 255; if(endGreen < 0) endGreen = 0; var endBlue = Math.round((blue1 * Col1Fraction) + (blue2 * (1 - Col1Fraction))); if(endBlue > 255) endBlue = 255; if(endBlue < 0) endBlue = 0; return "#" + IntToHex(endRed)+ IntToHex(endGreen)+ IntToHex(endBlue); } /* Converts a number to hexadecimal format */ function IntToHex(strNum) { base = strNum / 16; rem = strNum % 16; base = base - (rem / 16); baseS = MakeHex(base); remS = MakeHex(rem); return baseS + '' + remS; } /* gets the hex bits of a number */ function MakeHex(x) { if((x >= 0) && (x <= 9)) { return x; } else { switch(x) { case 10: return "A"; case 11: return "B"; case 12: return "C"; case 13: return "D"; case 14: return "E"; case 15: return "F"; } } } /* For a pixel cut by the line determines the fraction of the pixel on the 'inside' of the line. Returns a number between 0 and 1 */ function pixelFraction(x, y, r) { var pixelfraction = 0; /* determine the co-ordinates of the two points on the perimeter of the pixel that the circle crosses */ var xvalues = new Array(1); var yvalues = new Array(1); var point = 0; var whatsides = ""; // x + 0 = Left var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x,2))); if ((intersect >= y) && (intersect < (y+1))) { whatsides = "Left"; xvalues[point] = 0; yvalues[point] = intersect - y; point = point + 1; } // y + 1 = Top var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y+1,2))); if ((intersect >= x) && (intersect < (x+1))) { whatsides = whatsides + "Top"; xvalues[point] = intersect - x; yvalues[point] = 1; point = point + 1; } // x + 1 = Right var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x+1,2))); if ((intersect >= y) && (intersect < (y+1))) { whatsides = whatsides + "Right"; xvalues[point] = 1; yvalues[point] = intersect - y; point = point + 1; } // y + 0 = Bottom var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y,2))); if ((intersect >= x) && (intersect < (x+1))) { whatsides = whatsides + "Bottom"; xvalues[point] = intersect - x; yvalues[point] = 0; } /* depending on which sides of the perimeter of the pixel the circle crosses calculate the fraction of the pixel inside the circle */ switch (whatsides) { case "LeftRight": pixelfraction = Math.min(yvalues[0],yvalues[1]) + ((Math.max(yvalues[0],yvalues[1]) - Math.min(yvalues[0],yvalues[1]))/2); break; case "TopRight": pixelfraction = 1-(((1-xvalues[0])*(1-yvalues[1]))/2); break; case "TopBottom": pixelfraction = Math.min(xvalues[0],xvalues[1]) + ((Math.max(xvalues[0],xvalues[1]) - Math.min(xvalues[0],xvalues[1]))/2); break; case "LeftBottom": pixelfraction = (yvalues[0]*xvalues[1])/2; break; default: pixelfraction = 1; } return pixelfraction; } // This function converts CSS rgb(x, x, x) to hexadecimal function rgb2Hex(rgbColour) { try{ // Remove rgb() var rgbValues = rgbColour.substring(4, rgbColour.indexOf(")")); // Split RGB into array var rgbArray = rgbValues.split(", "); // Get RGB values var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); // Build hex colour code var hexColour = "#" + IntToHex(red) + IntToHex(green) + IntToHex(blue); } catch(e){ alert("There was an error converting the RGB value to Hexadecimal in function rgb2Hex"); } return hexColour; } // Function by Simon Willison from sitepoint.com function setOpacity(obj, opacity) { opacity = (opacity == 100)?99.999:opacity; // IE/Win obj.style.filter = "alpha(opacity:"+opacity+")"; // Safari<1.2, Konqueror obj.style.KHTMLOpacity = opacity/100; // Older Mozilla and Firefox obj.style.MozOpacity = opacity/100; // Safari 1.2, newer Firefox and Mozilla, CSS3 obj.style.opacity = opacity/100; } /* Returns index if the passed value is found in the array otherwise returns false. */ function inArray(array, value) { for(var i = 0; i < array.length; i++){ // Matches identical (===), not just similar (==). if (array[i] === value) return i; } return false; } /* Returns true if the passed value is found as a key in the array otherwise returns false. */ function inArrayKey(array, value) { for(key in array){ // Matches identical (===), not just similar (==). if(key === value) return true; } return false; } // Attaches onload event cross browser function xAttachEventOnLoad(event, func) { // Attach event if(window.addEventListener) window.addEventListener(event, func, false); else if(window.attachEvent) window.attachEvent("on" + event, func); else window.onload = func; }