Animated dropdown checkboxes and creating custom on-hover events

For those who missed it, PerformanceG2 is sponsoring my trip to the IOD this year. In return, I’ve written a couple of articles for their blog.

The first is a fancy way of converting
needing-to-scroll-for-prompts-make-users-angry

To
sliders-are-awesome

This is a very easy technique to use, simply copy in the main script into an HTML item at the top of the page, and add another script at the bottom to call the functions. Since it doesn’t use the 10.2 Prompt API, you can implement it in every version since 8.4. To learn more about that technique, read the post here.

The next technique is a bit more interesting (at least for me). There have been many times where clients have asked for a way to add more insights to the tooltips in charts. For example, users may want to hover over a micro chart and see a magnified version:
Magnifying Microcharts

In that image each chart had the country ID hidden right next to it. Hovering over the chart would then unhide a div with the same ID and position it directly over the cursor. Moving away from the chart would then hide it.

The same fading functions were used for this next technique:
filtering a list

Each area in the map has an onhover event attached. There are some internal Cognos JS functions that will pull the contextual data of that area. So if you’re hovering over a dot, the functions would return the series, category, and measure of the dot. Hovering over a legend would return that specific series. Since this is referencing internal Cognos JS functions I can’t guarantee that it will work in previous (or future) versions.

Read up on that technique here.

It looks like the post is down. The popups report XML can be found here: Popups on Hover Report XML (1677 downloads)

updated animated checkbox prompt: updated-animated-checkbox.txt (989 downloads)

Cognos 10.1.1 bug: Charts breaking when switching between tabs

An annoying bug has been reported by several of my clients.

Any portal tab containing a chart will occasionally break when the user clicks away then returns:

If the user were to click on Public Folders, then return to the portal tab, suddenly the chart images are broken.

While I can’t explain why this is happening, I’m guessing that Cognos is flushing the image from the cache when the user leaves the page. When the user returns the image is no longer in the cache, so it’s returns a broken image.

Fortunately the refreshing the report will return the chart so this gives us a partial solution. If we can write a script that detects the state of the image (if it’s broken or not) we can have the portlet refresh.

First the report should be wrapped in a div with the display set to none. This will prevent users from seeing the broken charts. Second the chart itself should be wrapped in a div to give the function a place to start looking for broken images.

The function itself is fairly simple:

function checkImg()
{
var reportWrapper = document.getElementById('reportWrapper');
var chartWrapper = document.getElementById('chartWrapper');
var message = document.getElementById('message');
var img = chartWrapper.getElementsByTagName('IMG');
message.innerHTML = "checking image";
if (img[0].readyState == 'uninitialized') {refreshReport();message.innerHTML = "refreshing report";}
else {reportWrapper.style.display="";message.innerHTML = "";}

}

It checks the image’s readyState attribute. If it’s unitialized, the image is broken and the report should be refreshed, otherwise everything is fine and show the report.

The refresh function is from one of the IBM knowledge base articles.

function refreshReport()
{
var intval;
var fW = (typeof getFormWarpRequest == "function" ? getFormWarpRequest() : document.forms["formWarpRequest"]);
if ( !fW || fW == undefined)
{

    fW = ( formWarpRequest_THIS_ ? formWarpRequest_THIS_ : formWarpRequest_NS_ );

}
var preFix = "";
if (fW.elements["cv.id"])
{

    preFix = fW.elements["cv.id"].value;

}
var nameSpace = "oCV" + preFix;
if(intval!="")
{

    self.clearInterval(intval);
    intval="";

}
self["RunReportInterval"] = self.setInterval( nameSpace + ".getRV().RunReport()",'0' );
intval = self["RunReportInterval"];
}

Finally the checkImg function needs to be called. It can’t be called as soon as the page is loaded, because the chart image itself takes a moment to load. If the function is called before the chart is loaded, it will refresh the page in an infinite loop. Instead it’s best to wait a moment. I find that 1 second works well.

setTimeout("checkImg()",1000);

Now when the page loads it will wait 1 second and check the chart. If the image is broken it will refresh the page:

It’s worth mentioning that this is a band-aid solution (and not a great one either). The true fix needs to come from IBM. There is an APAR open for this issue, but so far no hotfix. Slower computers may take longer to load the image, and may result in the user being stuck in an infinite loop. Additionally the report will only display after the function has a chance to check the image, effectively increasing the load time of the report by however long is set in the setTimeout.

Report XML: (Remember to create a page and add this to a cognos viewer)

<report xmlns="http://developer.cognos.com/schemas/report/8.0/" useStyleVersion="10" expressionLocale="en-us">
				<modelPath>/content/folder[@name='Samples']/folder[@name='Models']/package[@name='GO Data Warehouse (query)']/model[@name='model']</modelPath>
				<drillBehavior modelBasedDrillThru="true"/>
				<queries>
					<query name="Query1">
						<source>
							<model/>
						</source>
						<selection><dataItem name="Gross margin" aggregate="automatic"><expression>[Sales (query)].[Gross margin]</expression><XMLAttributes><XMLAttribute name="RS_dataUsage" value="fact" output="no"/></XMLAttributes></dataItem><dataItem name="Product line" aggregate="none" rollupAggregate="none"><expression>[Sales (query)].[Products].[Product line]</expression><XMLAttributes><XMLAttribute name="RS_dataType" value="3" output="no"/><XMLAttribute name="RS_dataUsage" value="attribute" output="no"/></XMLAttributes></dataItem></selection>
					</query>
				</queries>
				<layouts>
					<layout>
						<reportPages>
							<page name="Page1"><style><defaultStyles><defaultStyle refStyle="pg"/></defaultStyles></style>
								<pageBody><style><defaultStyles><defaultStyle refStyle="pb"/></defaultStyles></style>
									<contents>
										<HTMLItem description="report Display None">
			<dataSource>
				<staticValue>&lt;div id="reportWrapper" style="display:none"&gt;</staticValue>
			</dataSource>
		</HTMLItem><HTMLItem description="Chart Wrapper">
			<dataSource>
				<staticValue>&lt;div id="chartWrapper"&gt;</staticValue>
			</dataSource>
		</HTMLItem><combinationChart showTooltips="true" maxHotspots="10000" refQuery="Query1" name="Combination Chart1">
								<legend>
									<legendPosition>
										<relativePosition/>
									</legendPosition>
									<legendTitle refQuery="Query1">
										<style>
											<defaultStyles>
												<defaultStyle refStyle="lx"/>
											</defaultStyles>
										</style>
									</legendTitle>
									<style>
										<defaultStyles>
											<defaultStyle refStyle="lg"/>
										</defaultStyles>
									</style>
								</legend>
								<ordinalAxis>
									<axisTitle refQuery="Query1">
										<style>
											<defaultStyles>
												<defaultStyle refStyle="at"/>
											</defaultStyles>
										</style>
									</axisTitle>
									<axisLine color="black"/>
									<style>
										<defaultStyles>
											<defaultStyle refStyle="al"/>
										</defaultStyles>
									</style>
								</ordinalAxis>
								<numericalAxisY1>
									<axisTitle refQuery="Query1">
										<style>
											<defaultStyles>
												<defaultStyle refStyle="at"/>
											</defaultStyles>
										</style>
									</axisTitle>
									<gridlines color="#cccccc"/>
									<axisLine color="black"/>
									<style>
										<defaultStyles>
											<defaultStyle refStyle="al"/>
										</defaultStyles>
									</style>
								</numericalAxisY1>
								<combinationChartTypes>
									<bar/>
								</combinationChartTypes>
								<style>
									<defaultStyles>
										<defaultStyle refStyle="ch"/>
									</defaultStyles>
								</style>
							<commonClusters><chartNodes><chartNode><chartNodeMembers><chartNodeMember refDataItem="Product line"><chartContents><chartTextItem><dataSource><memberCaption/></dataSource></chartTextItem></chartContents></chartNodeMember></chartNodeMembers></chartNode></chartNodes></commonClusters><defaultChartMeasure refDataItem="Gross margin"/></combinationChart>
									<HTMLItem description="closing divs and script">
			<dataSource>
				<staticValue>&lt;/div&gt;
&lt;/div&gt;
&lt;div id="message"&gt;
&lt;/div&gt;
&lt;script&gt;

function checkImg()
{
var reportWrapper = document.getElementById('reportWrapper');
var chartWrapper = document.getElementById('chartWrapper');
var message = document.getElementById('message');
var img = chartWrapper.getElementsByTagName('IMG');
message.innerHTML = "checking image";
if (img[0].readyState == 'uninitialized') {refreshReport();message.innerHTML = "refreshing report";}
else {reportWrapper.style.display="";message.innerHTML = "";}

}

function refreshReport()
{
var intval;
var fW = (typeof getFormWarpRequest == "function" ? getFormWarpRequest() : document.forms["formWarpRequest"]);
if ( !fW || fW == undefined)
{

    fW = ( formWarpRequest_THIS_ ? formWarpRequest_THIS_ : formWarpRequest_NS_ );

}
var preFix = "";
if (fW.elements["cv.id"])
{

    preFix = fW.elements["cv.id"].value;

}
var nameSpace = "oCV" + preFix;
if(intval!="")
{

    self.clearInterval(intval);
    intval="";

}
self["RunReportInterval"] = self.setInterval( nameSpace + ".getRV().RunReport()",'0' );
intval = self["RunReportInterval"];
}

setTimeout("checkImg()",1000);
&lt;/script&gt;
</staticValue>
			</dataSource>
		</HTMLItem></contents>
								</pageBody>
								<pageHeader>
									<contents>
										<block><style><defaultStyles><defaultStyle refStyle="ta"/></defaultStyles></style>
											<contents>
												<textItem><style><defaultStyles><defaultStyle refStyle="tt"/></defaultStyles></style>
													<dataSource>
														<staticValue>This works</staticValue>
													</dataSource>
												</textItem>
											</contents>
										</block>
									</contents>
									<style>
										<defaultStyles>
											<defaultStyle refStyle="ph"/>
										</defaultStyles>
										<CSS value="padding-bottom:10px"/>
									</style>
								</pageHeader>
								<pageFooter>
									<contents>
										<table>
											<tableRows>
												<tableRow>
													<tableCells>
														<tableCell>
															<contents>
																<date>
																	<style>
																		<dataFormat>
																			<dateFormat/>
																		</dataFormat>
																	</style>
																</date>
															</contents>
															<style>
																<CSS value="vertical-align:top;text-align:left;width:25%"/>
															</style>
														</tableCell>
														<tableCell>
															<contents>
																<pageNumber/>
															</contents>
															<style>
																<CSS value="vertical-align:top;text-align:center;width:50%"/>
															</style>
														</tableCell>
														<tableCell>
															<contents>
																<time>
																	<style>
																		<dataFormat>
																			<timeFormat/>
																		</dataFormat>
																	</style>
																</time>
															</contents>
															<style>
																<CSS value="vertical-align:top;text-align:right;width:25%"/>
															</style>
														</tableCell>
													</tableCells>
												</tableRow>
											</tableRows>
											<style>
												<defaultStyles><defaultStyle refStyle="tb"/></defaultStyles>
												<CSS value="border-collapse:collapse;width:100%"/>
											</style>
										</table>
									</contents>
									<style>
										<defaultStyles>
											<defaultStyle refStyle="pf"/>
										</defaultStyles>
										<CSS value="padding-top:10px"/>
									</style>
								</pageFooter>
							</page>
						</reportPages>
					</layout>
				</layouts>
			<XMLAttributes><XMLAttribute name="RS_CreateExtendedDataItems" value="true" output="no"/><XMLAttribute name="listSeparator" value="," output="no"/><XMLAttribute name="RS_modelModificationTime" value="2011-06-09T13:50:33.233Z" output="no"/></XMLAttributes><reportName>Test 1</reportName></report>

Fusion Charts in Cognos – Links

In my previous post I discussed a basic column graph, quarters and revenue. In this post I’ll expand on that basic graph by adding the link parameter.

The link parameter will allow us to run JavaScript functions to call Parameterized URLS.

Open the XML I attached to the previous post.

We’ll start with imitating a drilldown. To do this we need to have each column contain a link to the same report, passing the MUN. The x-axis should be a higher level than the Quarters. Since it’s supposed to receive MUN we’ll use a prompt macro with a default value of the year level. Rename the existing Data Item to Time, and replace the expression with:

#prompt('Time','mun','[great_outdoors_company].[Years].[Years].[Year]','children(','',')')#

The macro will wrap whatever member is sent to it with children().

We will also need to explicitly set the MUN being set. Create a new data item in the query called TimeMUN.

roleValue('_memberUniqueName',[Time])

This will return the MUN as a string value. Useful for inserting it into an HTML item.

Now that the query is set, we need a way of calling the report. Instead of putting the full URL for the report directly into each column, we can instead call a JavaScript function. At the top of the page drag in a new HTML item, set it to Report Expression, and paste in the following code:

[sourecode]’
var report=”../cgi-bin/cognosisapi.dll?b_action=xts.run&m=portal/report-viewer.xts&ui.action=run&ui.object=’+URLEncode(ReportPath())+”’

function drillDown(mun)
{
window.open(report+”&run.prompt=false&p_Time=”+mun,”_self”)

}
‘[/sourcecode]

As you can see the report path is being generated from the Cognos report function ReportPath. This will only work from Cognos Connection, so you may want to manually put the full path of the report so you can run it from Report Studio.

Now for the link itself.

Right now you should have a total of 7 HTML items generating the HTML for the chart. 5 of those should be inside a repeater defining the categories and associated values. Insert a new HTML item after the Revenue HTML item with the following expression:

' link='JavaScript:drillDown(&quot;

The first quotes is to close the value from the revenue. The &quot is important as regular quotes won’t work as that would close the link string, and doublequotes won’t work as that would close the value string from the object tag.

Insert another HTML item to the right of Link, give it the description MUN, and set the source type to Data Item Value, with the Data Item Value set to TimeMUN.

Now modify the /set HTML Item to

&quot;);' />

Save and run it from the Cognos Connection and the first page should look like:

And clicking on 2006 should return:

The actual HTML generated will look something like:

<OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="600" height="400" id="Column3D" >    <param name="movie" value="../samples/images/CPM/FusionChartsFree/FCF_Column3D.swf" />    <param name="FlashVars" value="&chartWidth=600&chartHeight=400&dataXML=<graph caption='Revenue (K$)' xAxisName='Period' yAxisName='Revenue' rotateNames='1' showNames='1' numberPrefix='$' numberSuffix='K' decimalPrecision='0' formatNumberScale='0'><set name='2004' value='34750.6' link='JavaScript:drillDown(&quot;[great_outdoors_company].[Years].[Years].[Year]->:[PC].[@MEMBER].[20040101-20041231]&quot;);' /><set name='2005' value='62540.9' link='JavaScript:drillDown(&quot;[great_outdoors_company].[Years].[Years].[Year]->:[PC].[@MEMBER].[20050101-20051231]&quot;);' /><set name='2006' value='74285' link='JavaScript:drillDown(&quot;[great_outdoors_company].[Years].[Years].[Year]->:[PC].[@MEMBER].[20060101-20061231]&quot;);' /></graph>">    <param name="quality" value="high" />  </object>

The same method can be used as drillthroughs.

A little more difficult is to do a drill-up. I’ll leave that as an exercise that I will leave to my readers.

As usual, the XML is below.

<report xmlns="http://developer.cognos.com/schemas/report/3.0/" expressionLocale="he" interactivePageBreakByFrame="true"><!--RS:8.2-->
	<modelPath>/content/package[@name='Great Outdoors Company']/model[@name='model']</modelPath>
	<layouts>
		<layout>
			<reportPages>
				<page class="pg" name="Page1">
					<pageBody class="pb">
						<contents>

							<HTMLItem description="drillDown">
								<dataSource>

								<reportExpression>'&lt;script&gt;
var report=''../cgi-bin/cognosisapi.dll?b_action=xts.run&amp;m=portal/report-viewer.xts&amp;ui.action=run&amp;ui.object='+URLEncode(ReportPath())+'''

function drillDown(mun)
{
   window.open(report+''&amp;run.prompt=false&amp;p_Time=''+mun,''_self'')

}

&lt;/script&gt;'</reportExpression></dataSource>
							</HTMLItem>
							<selectValue parameter="Product" refQuery="Products" multiSelect="false" range="false" required="false" autoSubmit="true"><useItem refDataItem="Product line"/></selectValue>
							<textBox numbersOnly="false" multiSelect="false" range="false" required="false" parameter="Time"><style><CSS value="display:none"/></style></textBox>
							<table class="tb"><tableRows><tableRow><tableCells><tableCell><contents/></tableCell></tableCells></tableRow><tableRow><tableCells><tableCell><contents>

													</contents></tableCell></tableCells></tableRow><tableRow><tableCells><tableCell><contents><HTMLItem description="First">
														<dataSource>
															<staticValue>  &lt;OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="600" height="400" id="Column3D" &gt;
    &lt;param name="movie" value="../samples/images/CPM/FusionChartsFree/FCF_Column3D.swf" /&gt;
    &lt;param name="FlashVars" value="&amp;chartWidth=600&amp;chartHeight=400&amp;dataXML=&lt;graph caption='Revenue (K$)' xAxisName='Period' yAxisName='Revenue' rotateNames='1' showNames='1' numberPrefix='$' numberSuffix='K' decimalPrecision='0' formatNumberScale='0'&gt;</staticValue>
														</dataSource>
													</HTMLItem>
													<repeater refQuery="Query1" rowsPerPage="132123">
														<contents><HTMLItem description="set name=">
																<dataSource>
																	<staticValue>&lt;set name='</staticValue>
																</dataSource>
															</HTMLItem>
															<HTMLItem description="Time">
																<dataSource>
																	<dataItemValue refDataItem="Time"/></dataSource>
															</HTMLItem>
															<HTMLItem description=" value=">
																<dataSource>
																	<staticValue>' value='</staticValue>
																</dataSource>
															</HTMLItem>
															<HTMLItem description="Revenue">
																<dataSource>
																	<reportExpression>number2string([Query1].[Revenue]/1000)</reportExpression></dataSource>
															</HTMLItem>

															<HTMLItem description="link">
																<dataSource>
																	<staticValue>' link='JavaScript:drillDown(&amp;quot;</staticValue>
																</dataSource>
															</HTMLItem>
															<HTMLItem description="MUN">
																<dataSource>
																	<dataItemValue refDataItem="TimeMUN"/></dataSource>
															</HTMLItem>
															<HTMLItem description="/set">
																<dataSource>
																	<staticValue>&amp;quot;);' /&gt;</staticValue>
																</dataSource>
															</HTMLItem>
														</contents>
														<propertyList><propertyItem refDataItem="Time"/><propertyItem refDataItem="Revenue"/></propertyList></repeater><HTMLItem description="Last">
										<dataSource>
											<staticValue>&lt;/graph&gt;"&gt;
    &lt;param name="quality" value="high" /&gt;
  &lt;/object&gt;
</staticValue>
										</dataSource>
									</HTMLItem></contents></tableCell></tableCells></tableRow></tableRows><style><CSS value="border-collapse:collapse"/></style></table><textItem><dataSource><staticValue>  &lt;OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="600" height="400" id="Column3D" &gt;    &lt;param name="movie" value="../samples/images/CPM/FusionChartsFree/FCF_Column3D.swf" /&gt;    &lt;param name="FlashVars" value="&amp;chartWidth=600&amp;chartHeight=400&amp;dataXML=&lt;graph caption='Revenue (K$)' xAxisName='Period' yAxisName='Revenue' rotateNames='1' showNames='1' numberPrefix='$' numberSuffix='K' decimalPrecision='0' formatNumberScale='0'&gt;</staticValue></dataSource></textItem><repeater refQuery="Query1" rowsPerPage="132123">
														<contents><textItem><dataSource><staticValue>&lt;set name='</staticValue></dataSource></textItem>
															<HTMLItem description="Time">
																<dataSource>
																	<dataItemValue refDataItem="Time"/></dataSource>
															</HTMLItem>
															<HTMLItem description=" value=">
																<dataSource>
																	<staticValue>' value='</staticValue>
																</dataSource>
															</HTMLItem>
															<HTMLItem description="Revenue">
																<dataSource>
																	<reportExpression>number2string([Query1].[Revenue]/1000)</reportExpression></dataSource>
															</HTMLItem>

															<textItem><dataSource><staticValue>' link='JavaScript:drillDown(&amp;quot;</staticValue></dataSource></textItem>
															<HTMLItem description="MUN">
																<dataSource>
																	<dataItemValue refDataItem="TimeMUN"/></dataSource>
															</HTMLItem>
															<textItem><dataSource><staticValue>&amp;quot;);' /&gt;</staticValue></dataSource></textItem>
														</contents>
														<propertyList><propertyItem refDataItem="Time"/><propertyItem refDataItem="Revenue"/></propertyList></repeater><textItem><dataSource><staticValue>&lt;/graph&gt;"&gt;    &lt;param name="quality" value="high" /&gt;  &lt;/object&gt;</staticValue></dataSource></textItem></contents>
					</pageBody>
				</page>
			</reportPages>
		</layout>
	</layouts>
<queries><query name="Query1">
			<source>
				<model/>
			</source>
			<selection><dataItem name="Time" aggregate="none"><expression>#prompt('Time','mun','[great_outdoors_company].[Years].[Years].[Year]','children(','',')')#</expression></dataItem><dataItem name="TimeMUN" aggregate="none"><expression>roleValue('_memberUniqueName',[Time])</expression></dataItem><dataItem name="Revenue" aggregate="none" rollupAggregate="none"><expression>[great_outdoors_company].[Measures].[Revenue]</expression></dataItem></selection>
		<slicer><slicerMemberSet>#prompt('Product','mun','[great_outdoors_company].[Products].[Products].[Products]-&gt;:[PC].[@MEMBER].[Products]')#</slicerMemberSet></slicer></query>
	<query name="Products"><source><model/></source><selection><dataItem name="Product line" aggregate="none"><expression>[great_outdoors_company].[Products].[Products].[Product line]</expression></dataItem></selection></query></queries></report>