Formatting the Controls from Page Styles

[Previous] [Next]

If you run the solution shown in this chapter, you will notice that the Chart controls on the pages entitled Historical Charts and Current Call Levels blend in well with the colors and fonts used on the rest of the page. You might think that this was just custom formatting implemented in code, but actually it was done in a much more generic way (described momentarily) that you can use to format any Chart control to match the containing page's style information.

Linked and embedded style sheets allow web developers to separate formatting information from their content and layout information in a web page. Keeping colors and fonts consistent throughout a site is often difficult when you embed formatting information into the HTML document using <font> tags. However, you can use style sheets to define what formatting the browser should use when rendering specified HTML elements. This feature is known as cascading style sheets (CSS) and is documented in the MSDN libraries. I use linked style sheets (meaning the style sheet exists as a separate file and is linked into each page) in all this book's examples and solutions so that the pages look consistent.

Style sheets allow you to specify formatting for any HTML element, but unfortunately they have no control over the content displayed within a COM control on a web page. Because the Office Web Components support all the HTML color and font names Microsoft Internet Explorer supports, you can write code to automatically format your components (in this case the Chart component) to match the styles in your page. Let's take a look at how I did this in the Helpdesk Reporting solution.

I implemented the control formatting code as a generic set of functions that you can include in any HTML page. It resides in a file called FormatControls.scp in the Scripts directory on the companion CD. To include this in the HistoricalCharts.htm page, I inserted the following HTML fragment:

 <!-- Common routines for formatting the Office Web Components  based on styles --> <script language=vbscript src="../Scripts/FormatControls.scp"> </script> 

In the HTML <script> tag, you can add an optional src attribute. The value for this attribute is the URL of another file containing the contents for the script block. In this case, I've used a relative URL to the FormatControls.scp file in the Scripts directory. This script file implements a number of functions, but the only one needed in this example is the FormatChartFromStyles function, used in the BindChart function:

 ' Format the chart FormatChartFromStyles cspace 

This function takes a reference to the entire Chart control, and it performs the rest of the formatting work inside the function.

Implementing Functions in the FormatControls.scp File

Let's look at the beginning of the FormatChartFromStyles function:

 Sub FormatChartFromStyles(cspace)     ' Local variables     Dim cht             ' Temporary WCChart object reference     Dim ax              ' Temporary WCAxis object reference     Dim ser             ' Temporary WCSeries object reference     Dim dls             ' Temporary WCDataLabels object reference     Dim vStyleVal       ' Temporary style value     Dim ct              ' Loop counter          ' Format the various elements of the ChartSpace     ' ChartSpace background     vStyleVal = FindStyleValue(Array("ChartSpace","TH"), _         "background-color")     If Not(IsEmpty(vStyleVal)) Then cspace.Interior.Color = vStyleVal          ' ChartSpace title     If cspace.HasChartspaceTitle Then         vStyleVal = FindStyleValue(Array("ChartspaceTitle","H2","H1"), _             "background-color")         If Not(IsEmpty(vStyleVal)) Then _             cspace.ChartspaceTitle.Interior.Color = vStyleVal                      SetFontInfo cspace.ChartspaceTitle, _             Array("ChartspaceTitle","H2","H1")     End If 'Has a title     ' ChartSpace legend     If cspace.HasChartspaceLegend Then         vStyleVal = FindStyleValue(Array("Legend","Body"), _             "background-color")         If Not(IsEmpty(vStyleVal)) Then _             cspace.ChartspaceLegend.Interior.Color = vStyleVal         SetFontInfo cspace.ChartspaceLegend, Array("Legend", "P")     End If 'Has a legend      

This function cycles through all those elements in the Chart control that can be formatted with color or fonts. Then it cycles through each chart, each series of each chart, and each axis of each chart, formatting each of those elements using the page's style information. This function uses two helper functions in the same script file: FindStyleValue and SetFontInfo. The FindStyleValue function finds style values for the requested selector and style attribute; SetFontInfo is a wrapper function that sets a number of font properties based on the specified selector.

Before I describe how to obtain style information, I want to define a few terms used in style sheets. To help define these terms, let's look at part of the style sheet used for this chapter's code (from Styles.css on the companion CD):

 body  {      background-color: Whitesmoke;       font-family: Tahoma;     color: Black;} p  {      color: Black;     font-family: Verdana;     font-size: 10pt; } h1  {     font-family: Tahoma;     font-size: 24pt;     font-weight: bold;     color: Indigo; } Legend  {     font-family: Tahoma;     font-size: 8pt; }      Axis  {     font-family: Tahoma;     font-size: 8pt;     color: Black; } PlotArea  {     background-color: Whitesmoke; } ValueAxis  {     font-family: Tahoma;     font-size: 8pt;     number-format: #,##0;     color: Maroon; } 

A style sheet is essentially a listing of formatting rules. Each rule starts with a logical element name called a selector, and within each rule, you can define a set of style attributes. A selector is often an HTML tag name such as <p> or <h1> or a class name such as td.button. However, you can also include additional names that are not known tags—for example, Legend. Internet Explorer will retain these selectors and expose them in the Document Object Model (DOM), but it will not know how to apply them automatically since it has no idea what Legend is. Style attributes are formatting definitions such as color: Indigo, which states that any element matching the selector should have the color indigo.

All the information from the style sheet is parsed and loaded into objects that you can use from scripts in the page. Given the name of a selector, you can find its style rule and ask for any of its style attributes such as color, background-color, or font-family. The FindStyleValue and GetStyleValue functions use these objects to extract the style value and return it, enabling the FormatChartFromStyles function to apply the same formatting value to the particular chart element. Since the Office Web Components support the same named colors as Internet Explorer, you can assign color values directly from the returned style attribute value to the chart element. Let's look at the GetStyleValue function first:

 Function GetStyleValue(sSelector, sAttributeName)     ' Local variables     Dim ctStyleSheet        ' Style sheet loop counter     Dim ctRule              ' Rule loop counter     Dim ssCur               ' Current styleSheet object reference          ' Check to see that we have at least one styleSheet     If document.styleSheets.length = 0 Then Exit Function          ' Loop over all styleSheets backward     ' (to get the ones with highest precedence first)     For ctStyleSheet = (document.styleSheets.length - 1) To 0 Step -1                  ' Grab a reference to the current style sheet         Set ssCur = document.styleSheets(ctStyleSheet)                  ' Make sure the style sheet is enabled         If Not(ssCur.disabled) Then                      ' Loop over all rules in the style sheet             For ctRule = 0 To ssCur.Rules.Length - 1                 ' If the selectorText = the selector we're looking for,                 ' get the value for the specified attribute                 If LCase(ssCur.Rules(ctRule).selectorText) = _                     LCase(sSelector) Then                     GetStyleValue = GetAttributeValue( _                                      ssCur.Rules(ctRule), _                                      sAttributeName)                     ' Since we found the selector and                     ' GetAttributeValue will get the attribute                     ' if it exists, it's OK to exit the function                     ' now and return what we have                     Exit Function                 End If 'Element we're looking for             Next 'ctRule         End If 'styleSheet is not disabled     Next 'ctStylesheet End Function 'GetStyleValue() 

GetStyleValue takes parameters indicating what selector and attribute name you want to get. The function loops over all style sheets in the current document in reverse order. (You might have both a linked style sheet and an embedded style block.) This ensures that you get the last style definition for the given selector because that will usually be the one that overrides all previous definitions. The code also checks that the style sheet is enabled before attempting to find a selector within it.

Unfortunately, this code must loop over the style rules in the style sheet, looking for one that has a selector property value equal to the requested value. You can define multiple rules that use the same selector, defining some style attributes in one rule and others in different rules. This code does not catch this condition and will simply attempt to use the first rule it finds involving the desired selector. This makes the function a bit faster because I can short-circuit the loop when I find the selector instead of always looping over all rules. Note that I use the LCase function from VBScript to make sure I compare the selector text in a case-insensitive way. You can also use StrComp to perform a case-insensitive comparison.

Once I find a rule involving the desired selector, I use another helper function called GetAttributeValue. This function contains a simple Select Case block that uses the appropriate style object property based on the desired attribute name:

 Function GetAttributeValue(rule, sAttributeName)     ' Local variables     Dim sCssText            ' Holder for CSS text     Dim nPosStart           ' Temporary start position pointer     Dim nPosEnd             ' Temporary end position pointer          ' Switch on the desired attribute name     Select Case LCase(sAttributeName)         Case "backgroundcolor", "background-color"             GetAttributeValue = rule.style.backgroundcolor         Case "color"             GetAttributeValue = rule.style.color         Case "fontfamily", "font-family"             GetAttributeValue = rule.style.fontFamily         Case "fontsize", "font-size"             GetAttributeValue = rule.style.fontSize         Case "fontweight", "font-weight"             GetAttributeValue = rule.style.fontWeight                                      Case Else             ' Custom style attribute             ' See whether we can find it in the cssText property             sCssText = rule.style.cssText             nPosStart = InStr(sCssText, sAttributeName)             If nPosStart > 0 Then                 ' Found it; now extract it                 nPosStart = nPosStart + Len(sAttributeName) + 1                 nPosEnd = InStr(nPosStart, sCssText, ";")                 If nPosEnd <= 0 Then nPosEnd = Len(sCssText) + 1                 GetAttributeValue = Trim(Mid(sCssText, nPosStart, _                     nPosEnd - nPosStart))             End If 'Found attribute in cssText     End Select 'sAttributeName End Function 'GetAttributeValue() 

Because no method for looking up a style value by string name exists, this function determines the appropriate property of the style object based on the specified style attribute name. It also has a long Case Else block that attempts to find attributes that are not part of the CSS standard but might be in the style sheet. A great example of this is the style information for the ValueAxis selector I showed you earlier. I defined an attribute called number-format, which is not part of the CSS standard but should be defined for a chart's value axis. The GetAttributeValue code parses the value for non-CSS attributes from the style object's cssText property. This property returns the original text from the section of the style sheet in which the current rule exists.

Now that you have a way to get any style attribute value for any selector and attribute name, you need a way to find values given an escalating list of selectors. Suppose you want to allow developers to specify a rule in the style sheet for the chart title. However, if they do not make this specification, you want to use the rule defined for H3. If H3 is not defined, you might want to use the rule for H2 instead. This escalation is done using the FindStyleValue function.

 Function FindStyleValue(asSelectors, sAttributeName)     ' Local variables     Dim ct          ' Loop counter          ' Loop over all the selectors until GetStyleValue returns     ' something other than Empty     For ct = LBound(asSelectors) To UBound(asSelectors)         FindStyleValue = GetStyleValue(asSelectors(ct), sAttributeName)         If Not(IsEmpty(FindStyleValue)) Then Exit Function     Next 'ct      End Function 'FindStyleValue 

This method simply loops over the array of selector names passed in the asSelectors argument, handing each one to the GetStyleValue function and determining whether it found a value. If it did, the function short-circuits and returns. If it did not, it continues with the next selector. If no value is found, the function simply returns Empty and the FormatChartFromStyles function skips formatting the chart element, leaving it set to its default values.

The last routine that I want to mention is the SetFontInfo function. Because the Chart control uses the same programming interface for any font information on any chart element, you can encapsulate the setting of font formatting information on a chart element in one function and reuse it. Here is what the function looks like:

 Sub SetFontInfo(obj, asSelectors)     ' Local variables     Dim vStyleVal           ' Temporary style value          vStyleVal = FindStyleValue(asSelectors, "font-family")     If Not(IsEmpty(vStyleVal)) Then obj.Font.Name = vStyleVal     vStyleVal = FindStyleValue(asSelectors, "font-size")     If Not(IsEmpty(vStyleVal)) Then obj.Font.Size = _         Left(vStyleVal, Len(vStyleVal) - 2)     vStyleVal = FindStyleValue(asSelectors, "font-weight")     If Not(IsEmpty(vStyleVal)) Then obj.Font.Bold = _         (LCase(vStyleVal) = "bold")     vStyleVal = FindStyleValue(asSelectors, "color")     If Not(IsEmpty(vStyleVal)) Then obj.Font.Color = vStyleVal     vStyleVal = FindStyleValue(asSelectors, "number-format")     If Not(IsEmpty(vStyleVal)) Then obj.NumberFormat = vStyleVal End Sub 'SetFontInfo() 

This code is just like the code in FormatChartFromStyles, but it operates on a generic object that has a Font property that exposes the Name, Size, Bold, and Color properties. It also applies the NumberFormat information if found.

Reusing the FormatChartFromStyles Function

You can reuse this code in your own solutions and modify it to include any additional functionality you need. To reuse this code in your solution, simply perform the following steps:

  1. Add the following script block to your HTML page, changing the URL of the src attribute to point to wherever you place the FormatControl.scp file:
  2.  <!--Common routines for formatting the Office Web Components  based on styles --> <script language=vbscript  src="../Scripts/FormatControls.scp"> </script> 

  3. Whenever you want to format a chart control using the current style information, execute this line of script:
  4.  FormatChartFromStyles MyChartSpace 

    In the above fragment, MyChartSpace is the name of your Chart control.



Programming Microsoft Office 2000 Web Components
Programming Microsoft Office 2000 Web Components (Microsoft Progamming Series)
ISBN: 073560794X
EAN: 2147483647
Year: 1999
Pages: 111
Authors: Dave Stearns

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net