Casual ideas for web development

Rounded Panel Without Images

17 Jul 2007

Panels with rounded borders are widely used in the web site design. So widely that it is hard to add something new. I just try to wrap existing ideas in the form of web control.

Features:
  • Can be set radius of the circle, back color and border color
  • Without images (pure HTML)
  • Only 130 lines of code
  • Easy to use (see examples below this article)
<cc:RoundedPanel ID="RoundedPanel1" runat="server" CssClass="r1" BorderColor="Gold" 
         BackColor="Beige" Radius="9"></cc:RoundedPanel>

I inherit control from WebControl. Mainly it will be a container for another elements so it needs PersistChildrenAttribute and ParseChildrenAttribute to be set correctly. BackColor and BorderColor properties have been defined in the base class, only radius of circle has to be added.

 [PersistChildren(true), 
 ParseChildren(false), 
 ToolboxData("<{0}:RoundedPanel runat=\"server\"></{0}:RoundedPanel>"),
 Designer(typeof(System.Web.UI.Design.ContainerControlDesigner ))]
 public class RoundedPanel : WebControl
 {
        [Browsable(true), DefaultValue(5), Category("Appearance")]
        public int Radius
        {
            get
            {
                return (int)(ViewState["Radius"] ?? 5);
            }
            set
            {
                ViewState["Radius"] = value;
            }
        }
  ...  
 

Here is my favorite site where I am looking for examples of the use of CSS in real life. I'd like to take one of those examples of boxes with rounded corners as a base for web control but unfortunately none of the implementation on the basis of DIV cannot properly stretch if inner content is larger then the given DIV width. But in the development of the sites with dynamically loadable content, this problem is not that it would be everywhere but rather predictable.

So I decide to take as a basis a TABLE element - don't judge severely, I am developer not web designer :).
The corners are made of blocks (B elements) of varying widths and with different borders (look at the picture). B element are taken taken on the sole reason that its name is shorter than DIV. And inasmuch as corners are built from n elements (n = radius), that gives some savings of HTML.

public override void RenderControl(HtmlTextWriter writer)
{
    //forms four corners
    StringBuilder sbTopLeft = new StringBuilder();
    StringBuilder sbTopRight = new StringBuilder();
    StringBuilder sbBottomLeft = new StringBuilder();
    StringBuilder sbBottomRight = new StringBuilder();
    for (int i = 0; i < Radius; i++)
    {
        sbTopLeft.AppendFormat("<b class='a{0}'></b>", i);
        sbTopRight.AppendFormat("<b class='b{0}'></b>", i);
        sbBottomLeft.AppendFormat("<b class='a{0}'></b>", Radius - i - 1);
        sbBottomRight.AppendFormat("<b class='b{0}'></b>", Radius - i - 1);
    }
    //renders upper part of the panel
    writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "0");
    writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "0");
    writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass);
    writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);
    if (!Width.IsEmpty)
        writer.AddStyleAttribute(HtmlTextWriterStyle.Width, Width.ToString());
    if (!Height.IsEmpty)
        writer.AddStyleAttribute(HtmlTextWriterStyle.Height, Height.ToString());
    writer.RenderBeginTag("table");
    writer.Write(string.Format(@"<tr>
<td class='l' align=right>{0}</td>
<td class='m mt'> </td>
<td class='r'>{1}</td>
</tr>
<tr>
<td class='m ml'> </td>
<td class='m'>", sbTopLeft, sbTopRight));
    //renders child controls
    base.RenderContents(writer);
    //renders bottom part of the panel
    writer.Write(string.Format(@"</td>
<td class='m mr'> </td>
</tr>
<tr>
<td class='l' align=right>{0}</td>
<td class='m mb'> </td>
<td class='r'>{1}</td>
</tr>", sbBottomLeft, sbBottomRight));
    writer.RenderEndTag();
}
 

Then I create styles based on selected colors and desired circle radius. They make all work.

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    //I register styles using RegisterClientScriptBlock because it hard to get desired style names by means
    //of proper function Page.Header.StyleSheet.RegisterStyle. Also if there are a few same panels on a page
    //the styles will be registered just once.
    if (!Page.ClientScript.IsClientScriptBlockRegistered(typeof(Page), CssClass))
    {
    	//gets color name in either "red" or "#f5d724" form 
        string backColorStr = BackColor.IsNamedColor ? BackColor.Name : "#"+BackColor.Name.Substring(2);
        string borderColorStr = BorderColor.IsNamedColor?BorderColor.Name:"#"+BorderColor.Name.Substring(2);
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("<style type='text/css'>");
        sb.AppendFormat(@".{0} .l b,.{0} .r b(background-color:{1};height:1px;overflow:hidden;display:block;)
.{0} .ml(border-left:1px solid {2};) 
.{0} .mr(border-right:1px solid {2};) 
.{0} .m(background-color:{1};)
.{0} .mt(border-top:1px solid {2};height:{4}px;font-size:1px;)
.{0} .ml,.{0} .mr(width:{3}px;font-size:1px;)
.{0} .mb(border-bottom:1px solid {2};height:{4}px;font-size:1px;)", 
               CssClass, backColorStr, borderColorStr, Radius, Radius - 1);
        int prevWidth = -1;
        //particular implementation for Internet Explorer is required if quirks mode is used.
        bool isIE = HttpContext.Current.Request.Browser.Browser.Equals("IE");
        for (int i = 0; i < Radius; i++)
        {
            double angle = Math.Asin((double)(Radius - i) / Radius);
            int width = (int)Math.Ceiling((Radius * Math.Cos(angle)));
            if (width - prevWidth < 2)
                sb.AppendFormat(".{0} .a{1}(width:{2}px;border-left:solid 1px {3})", 
                      CssClass, i, width, borderColorStr);
            else
            {
                if (isIE)
                    sb.AppendFormat(".{0} .a{1}(width:{2}px;border-left:solid {3}px {4})", 
                        CssClass, i, width, (width - prevWidth), borderColorStr);
                else
                    sb.AppendFormat(".{0} .a{1}(width:{2}px;border-left:solid {3}px {4})", 
                        CssClass, i, (1 + prevWidth), (width - prevWidth), borderColorStr);
            }
            if (width - prevWidth < 2)
                sb.AppendFormat(".{0} .b{1}(width:{2}px;border-right:solid 1px {3})",
                    CssClass, i, width, borderColorStr);
            else
            {
                if (isIE)
                    sb.AppendFormat(".{0} .b{1}(width:{2}px;border-right:solid {3}px {4})", 
                        CssClass, i, width, (width - prevWidth), borderColorStr);
                else
                    sb.AppendFormat(".{0} .b{1}(width:{2}px;border-right:solid {3}px {4})", 
                        CssClass, i, (1 + prevWidth), (width - prevWidth), borderColorStr);
            }
            prevWidth = width;
        }
        sb.Append("\r\n</style>");
        string styles = sb.ToString().Replace("(", "{").Replace(")", "}");
        Page.ClientScript.RegisterClientScriptBlock(typeof(Page), CssClass, styles);
    }
}
 

This is implementation in case of your page is processed as HTML (<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >). If the page is processed as XHTML (<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">) then remove the condition for Internet Explorer.

Source Code, 1.6 Kb

Examples

1.<cc:RoundedPanel ID="RoundedPanel1" runat="server" CssClass="r1" BorderColor="gold" 
        BackColor="beige" Radius="8" Width="200px" Height="200px"></cc:RoundedPanel>
 
   
 
2.<cc:RoundedPanel ID="RoundedPanel2" runat="server" CssClass="r1" BorderColor="gold" 
       BackColor="beige" Radius="8" Width="200px" Height="200px">
    <div style="background-color:#cccccc;width:300px">too wide content</div>
</cc:RoundedPanel>
 
 
too wide content
 
 
3.<cc:RoundedPanel ID="RoundedPanel3" runat="server" CssClass="r1" 
       BorderColor="gold" BackColor="beige" Radius="8">
    without predefined dimensions
</cc:RoundedPanel>    
 
  without predefined dimensions  
 
4.<cc:RoundedPanel ID="RoundedPanel4" runat="server" CssClass="r2" BorderColor="#396394" 
       BackColor="#d4ebff" Radius=15 Width="400px" Height="100px">    
       different colors, radius = 15
</cc1:RoundedPanel>    
 
  different colors, radius = 15  
 

About this blog

This is a personal blog of Mykola Tarasyuk, a web developer from Ukraine. It includes articles about ASP.Net, C#, Javascript and anything else that tickles the fancy of the author ...

Top 6 of 2009


All Articles

Locations of visitors to this page
Copyright © Mykola Tarasyuk, 2007-2010