Hello,
Can any please tell the below procedure.
what r the patch upgrade steps for sap BIA version 7.20 level 17 to level 26
Hello,
Can any please tell the below procedure.
what r the patch upgrade steps for sap BIA version 7.20 level 17 to level 26
Xcelsius already allows for dynamic coloring through the use of alerts. As powerful as that is, however, there are multiple cases where one would like a more powerful method to achieve dynamic colors. These include, for example:
Here is a simple tutorial to make that happen. We will change the color of a text label from red to green using a horizontal slider in two very simple steps.
1. Add the component for which you want dynamic colours
For this example, we'll change the color of a text label using a slider. So we'll add:
2. Write the Formulas
Add the formulas from the image blow. The formulas take the value from the slider (B1) and translate that into a color code (B2):
(click for zoomed-in view)
The cells B5:B7 convert the data into 3 numbers between 0 and 255, corresponding to the red, green, blue. Here, I defined the formulas so that 0=red and 100=green, with middle values interpolating between these two. Of course, you can replace these to anything you want. Cells C5:C7 simply convert those numbers into hexadecimal notation. Finally, B2 merges all values together into the final color string. Here's what it looks like in action:
And you're done!
Next Steps
This is of course only the beginning. It is straightforward to edit the formulas in B5:B7 to define any color gradient you want. In this example, I used only two colors (red and green) but this can be increased to any number you want.
Hi All,
Attached below link is Dashboard tutorial for new learners of SAP BO and SAP Professionals which was developed in dashboard itself and it helps you to understand about the dashboard components and gives you the easiest way to develop the dashboard (Xcelsius). Simply I could describe it as "Dashboard about Dashboard".
https://docs.google.com/file/d/0B_LsQtxd85s8RklUQ040SGdoYjQ/edit?usp=sharing
Step 1:
Open the above link on new browser.
Step 2:
Now you could see the download option and download the file.
Step 3:
And open the file.
Password : incorrect
Thanks
Vijay Muniraj
Here is a trick to show Sales and forecast in different colors in the same chart.
Well there are two ways of doing it.
1. Using Two Series:
Use one series for the for the actual data, leave the rest column (predicted months) Blank.
Now in one another row keep only the predicted month’s data.
Leave the current months empty.
Q=Quantity , R=Revenue
You can map these 6 series to your chart. (I have taken only the revenue , which means 3 series-es )
2. Using Progress Bar:
Keep Your date in MMYYYY Format as displayed above.
In cell
A1 = TEXT(TODAY(),”yyyymm”)
//To note the year and month.
One cell (drag it over to the whole row) = IF(B1="","",IF(B1>=$A$1,0,1))
//This will check if the month there is less than the today’s month. (Actuals)
=Sum(this row) //This will be the data for the progress bar.
One cell (drag it over to the whole row) =IF(B1="","",1)
//To check the number of columns populated.
=Sum(this row) //This will the max limit of the progress bar.
In progress Bar:
General Tab: Scale-> Manual
Behavior Tab: Limits all fixed
Appearance Tab : Layout-> disable ticks ; Text -> uncheck everything ;
Color -> Different colors for marker and track.
Map data to the chart. In behavior tab of the chart , uncheck Ignore blank series.
Place this progress bar right below the chart.
Here is a quick trick on how to show alerts (up/down arrows) using character maps displayed using a label component in SAP Dashboards.
Every Font has a set of characters apart from the alphanumerics. And these set of characters vary from one font to another. These characters can be seen on character map in Windows.
1)
Open Character Map in windows by typing 'charmap' in Run:
2)
Scroll down the Character Map window to find some cool set of characters offered by the font. Some fonts like Arial, Times New Roman, etc. contain the arrows ▲▼ that we need. Select the character and copy it so that it can be pasted in the excel sheet of our Dashboards.
3)
The coloring is achieved by binding the label text color to the excel cell where a simple formula determines whether the color must be RED or GREEN based on the data value.
PS: Not all the fonts' characters are supported in SAP Dashboards. For instance, I eagerly tried out the cool characters of Windings Script but ended up with disappointment.
The following dashboard best practices are taking from the presentation that Romaric Sokhan and Alexandre Dussac of SAP will be giving at their hands –on lab at BI 2013 Amsterdam. This session was completely full at BI 2013 Las Vegas, and will be held in Amsterdam 11-13 June. See www.sapbi2013.com for more information.
Understanding dashboard initialization time
Six main factors to consider
Run queries after dashboard has initialized
Do not run queries during Initializing … message
Run queries after Initializing … message
For more information, on this Hands-on session and others, visit the web site at www.SAPBI2013.com and follow me on Twitter @BridgetKotelly.
With the continuous extension of mobile enablement in 2012, the Mobile Analytics suite of SAP offers the possibility of reaching the overall expectation of your business community in terms of dashboard requirements on mobile devices.
In this blog, I will share some examples of solutions that we have delivered at SAP to our internal Lines of Business, and how we can answer our needs using the right technology.
Explore and discover a maxim of information in a dashboard
A first use case of dashboards is when you need to compile different views of your data into a single framework, enabling your Business Users to slice and dice in all directions (dimensions) to find out all the information they need.
In this scenario, the main keyword is “freedom”. From a starting view on the data, you allow the End User the possibility to go to a completely different visualization from a data prospective and from a chart prospective.
This scenario fits perfectly with Exploration Views, one of the most recent features of SAP BusinessObjects Explorer offering a multi-view capability.
Advantages of this are the ease of creation, on top of HANA and/or universes – even a non-technical user can create these views – and the very large spectrum of data discovery offered to the End Users. In addition, the organization of the content, like a book with chapters and pages, is extremely convenient to guide your business community.
Perform complex, multi-dimensional analysis with guided navigation
If the first example is intended for “quick information to fast decision”, there are also scenarios where the primary need is to perform detailed analysis on different measures driving your business. In this case, the primary need is to the End User (generally a Business Analyst) the possibility to go as deep as needed into the details of the analysis, generally through successive levels of granularity/hierarchy.
SAP BusinessObjects Design Studio gives this possibility: the native connectivity to SAP Netweaver and SAP HANA offers the largest range in this type of business context. This tool is more technical than Exploration Views and the development is primarily intended for IT people and technical Business Power Users. The current version is mainly focused on analysis with high scalability and performance.
Interactive Performance dashboards for executives
Reaching the expectation executives have may require a complex combination of content, display, and interactivity in a way that is telling a story, not only showing data. We generally compare this as an advertisement: how to catch attention within a few seconds and give the right message(s) in less than 1 minute? This is the challenging goal you need to target.
SAP Dashboards (aka Xcelsius) offers this possibility and the recent HTML5 enablement since has allowed us to already rollout a few solutions where the context was exactly as described above.
With SAP BI Mobile, the User Experience and visual display have been optimized for each type of mobile device. In this context, web Intelligence can also be leveraged to create Operational Dashboards like “Reporting cockpits”. This is where the power of web Intelligence - support of multiple data providers, function language, and formatting – takes its full advantage to deliver solutions with high scalability and performance.
In conclusion, there is not one sole technology or several for Mobile Analytics. There is a business need and the right tool to address it. With the convergence of all Mobile Analytics into one single App (SAP BI Mobile), this technological question becomes transparent to the End User, who can access all his assets into the same mobile Application with no need to know which tool is behind.
Additional resources
More about SAP BusinessObjects Dashboards
The on-going (and in my view mistaken) obsession with “self-service" seems to lead many people to conclude that “Google is the Nirvana of end-user BI”. By which I think they mean that being able to type any question into a simple text box and get an answer is the best possible interface for asking a business question.
I disagree … both in terms of how you ask the question and in terms of the answer that you get!
Is this really the future of BI?
If I want sales information, I don’t want to have to type “what were total sales in Europe last quarter” and get a single number back only to have to then type “what were total costs in Europe last quarter” and either do a quick calculation to get profit or type yet another question. Little better would be the ability to say “show me sales in Europe last quarter broken down by country and quarters for the widget division” because now I am getting a little more structure but at the cost of having to type long and involved questions (which will doubtless be misinterpreted by the system).
And, on the answer side, I definitely don’t want a long list of links giving me alternative answers.
So, I have to ask, what it is that people think they are asking for when they say “Google is the Nirvana for BI”
A better vision of the future of BI
Fortunately, Google themselves have the right answer for us. It is a DASHBOARD. Here’s why …
I have been saying for a while (Four dashboard design lessons from the BBC Weather site) that the BBC weather site is one of the best examples of an interactive, predictive, “big” data dashboard you are likely to find. So it made me smile (to say the least) when I typed “weather” into Google the other day and the first thing I got back was … a DASHBOARD.
Watch the 62 second video below to find out what happens … and, as you will see, most of the page was filled not with a list of links but with a rather nice interactive, drillable dashboard.
So, while some people think that the future of BI is Google, I would strongly argue that this shows that Google themselves think that the future of end-user BI future is dashboards. And, I’m firmly with Google on this one.
More thoughts :-
For more on self-service (which this post started) check out my earlier post entitled Most users need BI Apps not "self-service" (here I use the terms “BI App” and “interactive dashboard” to mean the same thing, which one do you prefer ?).
If you want to find out more about what type of interactivity is required to make dashboards successful download the eBook “The Hierarchy of Interactive Dashboard Needs”
Pre-requisites:
Xcelsius Web connectivity Parameters to use
Building the Dashboard
Back in September I posted about “The HTML5 future of dashboards” which included a video of an interactive HTML5 dashboard which we had just demonstrated for the first time at the ASUG SBOUC conference in Orlando. The main point of this earlier post was to highlight that dashboards are a lot more than just a selection of summary grids and graphs and that HTML5 is a technology which can happily deliver the new breed of interactive dashboards which go so much further than offering mere “at a glance” summaries of data.
Back then, SAP BusinessObjects BI4 SP5 had not been released and so the HTML5 dashboard was delivered using our own technology, with the video in the post showing the results of combining our existing XIWS Anywhere iPad client and our next-generation product, code-named Antivia XA5. (Watch out for more details on XA5 here and across the BI-related internet in the next few months).
However with the release of BI4 SP5 (in late November) and the accompanying release of the SAP BusinessObjects Mobile iPad app (in mid-December), it is now possible to do the same thing inside the SAP technology stack (specifically SAP BusinessObjects Dashboards, the BI 4 platform and SAP BusinessObjects Mobile).
The video below shows a dashboard which was created in a couple of minutes using XWIS inside SAP BusinessObjects Dashboards being published to the BI Platform and then consumed through the BusinessObjects Mobile client on an iPad (if you would like to see how the dashboard was created with XWIS, check out the video in my original blog post or view the video directly here).
The XWIS-powered dashboard shown in this video was created using a proof-of-concept version of the SAP BusinessObjects HTML5 SDK, which SAP has indicated will form part of the 4.1 release currently scheduled to go into ramp-up in May.
If you would like to deliver interactive dashboards like this to your iPad users then please get in touch ; we are actively looking for customers who plan to be early adopters of 4.1 who would be interested in leading the market with this type of functionality.
Navigate to problem areas, or to known inspection points. A user can click on a air-conditioning unit with a reported maintenance issue.
Imagine if your workers could have access to 3D step-by-step visual work instructions that guide them through complex processes. Allowing them to interact with the model at each step of the process gives them a more complete view of the work required. These 3D work instructions can help organizations achieve optimal productivity through finer clarity in procedures and methods and improved process comprehension. Laying out assembly in this method can identify opportunities to improve processes and lead to compressed product delivery cycle times and save money through reduced training time.
Imagine being able to query and then visualize by color any and all parts in a 3D product model that have excessive warranty claim rates. Then drill-down and the dashboard can display information related to each part, helping you determine if excessive warranty claims are being driven by particular suppliers or perhaps being caused by a poor design in the product. Alerting will color the 3D model by your predefined targets so you can continually monitor your cost reduction process through finer clarity in procedures and methods and improved process comprehension. Laying out assembly in this method can identify opportunities to improve processes and lead to compressed product delivery cycle times and save money through reduced training time.
This picture illustrates an automobile engine in a dashboard illustrating warranty status using defect costs primarily centered on the electrical systems and cylinder heads and cover.
In my opinion, there are only some good books on the subject of visualization and infographics.
The most recent one is written by Alberto Cairo: “the functional art – an introduction to information graphics and visualization”. When I learned via twitter that Alberto offers an online course on the subject of visualization it was clear without a doubt that I will join the course.
The course started two week ago and our first task is to dismantle – sorry: to analyze – some pretty infographics. I chose a social media study with the title: “Social Demographics: Who’s Using Today’s Biggest Networks”. It is the attempt to visualize the demographic factors of users in different social networks – like gender, age, education and income.
This is what part of the original looks like:
Fig. 1: Extract from the original infographic
Many decorative details which make it difficult to understand the information. There is a lot of “noise” and lost space, but it looks nice and cool!
The social media networks are depicted as planets – with different sizes, although the planets’ areas really doesn’t represent the amount of users – and the demographic facts are shown as donut satellites. More planets, rockets, satellites and comets complete the picture. The whole infographic is low-keyed and shows additional information in texts for each network. A typical infographic …
There is only one problem: It is nearly impossible to read and understand the information shown.
Besides the fact that one should prefer bar charts to pie or donut charts. Old hat, let’s forget about this ….
The comprehension of the infographic is getting really complicated because the legend to the different demographic factors is only shown once, at the top of the graphic. It is very difficult to remember the colour scale when you scroll down to the different networks.
Another problem is that the colour theme of the legends does not only wander from dark to bright colours but these colours are chosen randomly. Since the arrangement of the coloured elements in the donut chart are not always the same, my eye-brain system is completely overwhelmed.
The infographic looks nice and cool, but its user value is naught.
But the icing on the cake is the graphic at the bottom: again rockets, satellite antennas and planets. Shall the area or the height mirror the values? Or both? Fine, that there is an additional value axis
As I wanted to rebuild the infographic I had to copy the values from the diagrams. Even with a copy of the legend in another open browser tab it was hard work – and it is not the fault of the second glass of wine.
Here is my alternative draft as a picture and interactive here:
Fig. 2: My alternative draft
The original has some interactivity, too: if you click on a social network in the first graphic, additional text information to this network is shown and the grey bar in the stacked chart is moving.
My aim was to enable comparison. Only with the comparison of the different networks it is possible to gain in sight. But for this goal we need the information at a glance – and graphically edited.
My design might not be as fancy as the original but I think it is much easier to read.
“Graphics, charts, and maps aren’t just tools to be seen, but to be read and scrutinized.”
Alberto Cairo, in: “the functional art – an introduction to information graphics and visualization”, S. XX.
One last point: On reading the graphic more closely it is obvious that there is a differentiation within the networks between “active users”, “unique visitors” and “registered users”. I can’t escape the feeling that here apples and oranges are compared.
the best, Lars
In my previous post, I described how to create a blinking label add-on for SAP BusinessObjects Dashboards 4.0. In this post, I shall describe how to create an On-Off toggle button add-on.
You must be thinking that as we already have a toggle button component in the tool, why to invest time on creating the same component again
. Actually recently I was watching some videos in Youtube on how to create custom skins for flex components. Being inspired by those, I tried to create a very simple add-on for SAP BusinessObjects Dashboards using custom skin in Flash Builder. Now, how does this differ from the existing toggle button component ? The component will actually look like the on-off button we see in an iPhone or iPad. The on/off state can be toggled by sliding the thumb
.
To keep it simple, I have kept only following features :
1. State Insertion : We can bind a cell in the excel model to insert the current state of the toggle button.
2. Default State : We can select a default state for the component.
3. Dynamic Visibility : We can specify a condition to show/hide the component.
The steps for creating this component are described below:
Actually this component is a Horizontal Slider component in Flex with two states - 0 and 1 and having a step-size of 1. Our first task is to create the skin for the flex HSlider component.
1. Launch Adobe Fireworks and create a new document.
2. Use a Rectangle Tool to draw a rectangle in the canvas.
3. Select the rectangle and apply following properties:
Width: 100
Height: 35
Fill Color: #0000FF
Border Color: #00008C
Tip size: 2
Stroke category: Soft Rounded
Roundness: 10px
4. Create a new Inner Shadow Filter for the rectangle as below:
5. Now draw a label 'ON' with the Text Tool. Make the width 50 and place it on top of the rectangle.
6. Similarly, create another label 'OFF' as below:
7. Group the 3 layers and give a name Track.
8. Till now, we have created the track of the slider. Now it is time to create the thumb which will slide.
Create another rectangle with following properties:
Width: 50
Height: 35
Fill Color: #EEEEEE
Border Color: #757584
Tip size: 1
Stroke category: Soft Rounded
Roundness: 10px
9. Add one Inner Glow Filter for the thumb like below:
10. Rename the new rectangle layer to Slider.
11. Place the thumb on top of track and check if it fits properly.
12. Click on File > Export and save in FXG format. Here I have saved the file as slider.fxg.
13. Now launch Adobe Flash Catalyst and create a new project.
14. Click File > Import > Adobe FXG File (.fxg)...
15. Import the slider.fxg file created by Adobe Fireworks.
16. Select two layers together and choose Horizontal Slider from the drop-down as shown:
17. Give a name as CustomSliderSkin.
18. Click Edit Parts.
19. Select Normal state.
20. Select Track layer and click Track (recommended) as shown:
21. Similarly, select Slider layer and click on Thumb (recommended).
22. Go to Project Library tab and click on Export Library Package button.
23. Save with name CustomSliderSkin.fxpl.
24. We have successfully created the skin for the component. Now in the next step we shall use this skin in Flash Builder to build the component.
1. Launch Flash Builder and click File > Import > Flash Builder Project...
2. Import the CustomSliderSkin.fxpl file we just created.
3. Create a new Flex Project with name OnOffButton.
4. In the properties of the project go to Flex Build Path section.
5. Choose Framework linkage as Merged into code. Click on Add project... button and select CustomSliderSkin. Click OK.
6. Under Flex compiler section, provide following command in Additional compiler arguments:
-locale en_US -isolate-styles=false -static-link-runtime-shared-libraries=true
7. Use Flex SDK 4.0 to compile the project.
8. Under src folder create a package with name com.yahoo.ari007_cse. Inside that, create an actionscript file with name OnOffButton.as.
9. Open the actionscript file and paste the code below:
| OnOffButton.as |
|---|
/* ------------------------------------------------------------------ ActionScript file: OnOffButton.as Author: Arijit Das Date Created: Jan 20, 2013 ------------------------------------------------------------------ */
package com.yahoo.ari007_cse { import components.MySlider;
import flash.events.Event;
import mx.containers.HBox; import mx.events.FlexEvent; import mx.styles.CSSStyleDeclaration; import mx.styles.StyleManager;
import spark.components.HSlider;
public class OnOffButton extends HBox{ /* ------------------------------------------------------------------ Properties ------------------------------------------------------------------ */ private var _slider:HSlider=new HSlider();
private var _defaultState:String="ON"; private var _defaultStateChanged:Boolean=true; private var _dynamicVisibility:Boolean=false; private var _visibleStatus:String=null; private var _visibleKey:String=null; private var _visibleKeyChanged:Boolean=false; private var _visibleStatusChanged:Boolean=true;
/* ------------------------------------------------------------------ Constructor ------------------------------------------------------------------ */ public function OnOffButton():void{ super(); }
/* ------------------------------------------------------------------ Static Function to determine if the component is being used at design time ------------------------------------------------------------------ */ public static function isInCanvas():Boolean{ var globalStyle:CSSStyleDeclaration=StyleManager.getStyleManager(null).getStyleDeclaration("global"); if (Boolean(globalStyle.getStyle("inCanvas"))==true){ return true; } return false; }
/* ------------------------------------------------------------------ When component is created, set visibility depending on property values ------------------------------------------------------------------ */ public function cretionCompleteHandler(event:Event):void{ if(!(_dynamicVisibility) || _visibleStatus==visibleKey || (_visibleStatus==null && visibleKey=="")){ this._slider.enabled=true; this.visible=true; } else{ this._slider.enabled=false; this.visible=false; } }
/* ------------------------------------------------------------------ defaultState Property ------------------------------------------------------------------ */ public function set defaultState(st:String):void{ if(_defaultState != st){ _defaultState=st; _defaultStateChanged=true; invalidateProperties(); } } public function get defaultState():String{ return _defaultState; } /* ------------------------------------------------------------------ visibleKey Property ------------------------------------------------------------------ */ public function set visibleKey(key:String):void{ _visibleKey=key; _visibleKeyChanged=true; invalidateProperties(); } public function get visibleKey():String{ return _visibleKey; } /* ------------------------------------------------------------------ visibleStatus Property ------------------------------------------------------------------ */ public function set visibleStatus(status:String):void{ _visibleStatus=status; _visibleStatusChanged=true; invalidateProperties(); } public function get visibleStatus():String{ return _visibleStatus; } /* ------------------------------------------------------------------ dynamicVisibility Property ------------------------------------------------------------------ */ public function set dynamicVisibility(flag:Boolean):void{ _dynamicVisibility=flag; } public function get dynamicVisibility():Boolean{ return _dynamicVisibility; } /* ------------------------------------------------------------------ state Property ------------------------------------------------------------------ */ [Bindable (event="valueChanged")] public function get state():String{ return (this._slider.value==0?"OFF":"ON"); }
/* ------------------------------------------------------------------ Dispatch event when state changes ------------------------------------------------------------------ */ public function stateChangedHandler(event:Event):void{ this.dispatchEvent(new Event("valueChanged")); }
/* ------------------------------------------------------------------ Build composite component ------------------------------------------------------------------ */ override protected function createChildren():void{ super.createChildren();
this._slider.value=(this._defaultState == "ON" ? 1 : 0); this._slider.setStyle("skinClass",components.CustomSliderSkin); this._slider.maximum=1; this._slider.minimum=0; this._slider.stepSize=1; this._slider.addEventListener(Event.CHANGE,stateChangedHandler); this.addChild(_slider);
this.minWidth=100; this.minHeight=35;
this.addEventListener(FlexEvent.CREATION_COMPLETE,cretionCompleteHandler); if(!(_dynamicVisibility) || _visibleStatus==_visibleKey || (_visibleStatus==null && _visibleKey=="")){ dispatchEvent(new Event("valueChanged")); } }
/* ------------------------------------------------------------------ Action taken after change in any property ------------------------------------------------------------------ */ override protected function commitProperties():void{ super.commitProperties();
/* ------------------------------------------------------------------- Check whether to update the default state ------------------------------------------------------------------- */ if (this._defaultStateChanged){ this._slider.value=(this._defaultState == "ON" ? 1 : 0); invalidateDisplayList(); _defaultStateChanged=false; }
/* ------------------------------------------------------------------- Check whether to show/hide the component ------------------------------------------------------------------- */ if(this._visibleKeyChanged || this._visibleStatusChanged){ if(!isInCanvas()){ if(!(_dynamicVisibility) || _visibleStatus==_visibleKey || (_visibleStatus==null && _visibleKey=="")){ this._slider.enabled=true; this.visible=true; this.dispatchEvent(new Event("valueChanged")); } else { this._slider.enabled=false; this.visible=false; } invalidateDisplayList(); } _visibleKeyChanged=false; _visibleStatusChanged=false; } } } } |
10. Open OnOffButton.mxml file under default package and paste the code below:
| OnOffButton.mxml |
|---|
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:ns="com.yahoo.ari007_cse.*"> <ns:OnOffButton height="100%" width="100%" /> </s:Application> |
11. Save all files and click File > Export Release Build. The component is created successfully.
1. Create a new Flex Project as OnOffButtonPropertySheet.
2. Go to project properties. Under Flex Build path, click on Add SWC... and browse to the file xcelsiusframework.swc located in <Dashboards_Installation_Dir>\Xcelsius 4.0\SDK\bin.
3. Use Flex SDK 4.0 to compile the project and use additional compiler argument :
-locale en_US -isolate-styles=false
4. Open OnOffButtonPropertySheet.mxml file under default package and paste the code below:
| OnOffButtonPropertySheet.mxml |
|---|
<?xml version="1.0" encoding="utf-8"?>
<!-- File Name: OnOffButtonPropertySheet.mxml Author: Arijit Das Date Created: Jan 20, 2013 -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="init();" backgroundColor="#F7F9FC" backgroundAlpha="1.0" preloaderChromeColor="#FEFEFF">
<mx:Script> <![CDATA[ import mx.containers.*; import mx.controls.*; import mx.core.Container; import mx.events.FlexEvent;
import xcelsius.binding.BindingDirection; import xcelsius.binding.tableMaps.input.InputBindings; import xcelsius.binding.tableMaps.output.OutputBindings; import xcelsius.propertySheets.impl.PropertySheetExternalProxy; import xcelsius.propertySheets.interfaces.IPropertySheetProxy; import xcelsius.propertySheets.interfaces.PropertySheetFunctionNamesSDK;
/* ----------------------------------------------------------------------------- The Xcelsius proxy between this Property Sheet and its Xcelsius custom component. ----------------------------------------------------------------------------- */ protected var proxy:IPropertySheetProxy = new PropertySheetExternalProxy(); /* ----------------------------------------------------------------------------- The name of the property that the user is (re-)binding. ----------------------------------------------------------------------------- */ protected var propertyToBind:String; /* ----------------------------------------------------------------------------- The current binding id (may be null if there is no binding) for the property the user is (re)-binding. ----------------------------------------------------------------------------- */ protected var currentBindingID:String;
/* ----------------------------------------------------------------------------- Default State Choice ----------------------------------------------------------------------------- */ [Bindable] protected var _state:Array = new Array("ON","OFF");
/* ----------------------------------------------------------------------------- Initialises this Property Sheet on load. ----------------------------------------------------------------------------- */ protected function init():void { proxy.addCallback(PropertySheetFunctionNamesSDK.GET_PROPERTIES_FUNCTION, getProperties); proxy.addCallback(PropertySheetFunctionNamesSDK.RESPONSE_BINDING_ID, this.continueBind); proxy.callContainer(PropertySheetFunctionNamesSDK.INIT_COMPLETE_FUNCTION);
loadProperties(); initValues(); }
protected function getProperties():Array { var persist:Array = new Array(); var persistObject:Object = new Object(); persistObject.name = "selectedTab"; persistObject.value = viewstack1.selectedIndex; persist.push(persistObject);
return persist; }
/* ----------------------------------------------------------------------------- Load the selected tab ----------------------------------------------------------------------------- */ protected function loadProperties():void { var persistProperties:Array = proxy.getPersist(["selectedTab"]); if (persistProperties != null && persistProperties.length != 0) { var propertyObject:Object = persistProperties[0]; var propertyValue:* = propertyObject.value; viewstack1.selectedIndex = propertyValue as int; } }
/* ----------------------------------------------------------------------------- Initialises this Property Sheet on load to show the current Xcelsius custom component property/style value ----------------------------------------------------------------------------- */ protected function initValues():void { var propertyValues:Array = proxy.getProperties([ "state", "defaultState", "visibleKey", "visibleStatus" ]);
var propertyValuesLength:int = (propertyValues != null ? propertyValues.length : 0); for (var i:int=0; i < propertyValuesLength; i++) { var propertyObject:Object = propertyValues[i]; var propertyName:String = propertyObject.name; var propertyValue:* = propertyObject.value; var bindingText:String = ""; switch (propertyName) { case "visibleStatus": bindingText = getPropertyBindDisplayName(propertyName); if (bindingText != null){ statustext.text = bindingText; visiblelabel.enabled=true; keylabel.enabled=true; keytext.enabled=true; keybind.enabled=true; } else { visiblelabel.enabled=false; keylabel.enabled=false; keytext.enabled=false; keybind.enabled=false; } break; case "visibleKey": bindingText = getPropertyBindDisplayName(propertyName); if (bindingText != null){ keytext.text = bindingText; } else keytext.text = propertyValue; break; case "state": bindingText = getPropertyBindDisplayName(propertyName); if (bindingText != null){ stateInsertion.text = bindingText; } break; case "defaultState": defaultstate.selectedIndex=_state.indexOf(propertyValue); break; default: break; } } }
/* ----------------------------------------------------------------------------- Returns the bind display name or null if not bound ----------------------------------------------------------------------------- */ protected function getPropertyBindDisplayName(propertyName:String):String { // Get the array of bindings for this property. var propertyBindings:Array = proxy.getBindings([propertyName]); if ((propertyBindings != null) && (propertyBindings.length > 0) && (propertyBindings[0].length > 0)) { // We have at least one binding for this property so pick the 1st one. // Note: [0][0] is 1st property in the array, then 1st binding for that property. var bindingID:String = propertyBindings[0][0]; return proxy.getBindingDisplayName(bindingID); } return null; }
/* ----------------------------------------------------------------------------- Allows the user to select the Excel spreadsheet cell to bind to an Xcelsius custom component property ----------------------------------------------------------------------------- */ protected function initiateBind(propertyName:String):void { // If there is an existing binding for this property show // that in the Excel binding selection window. // Store the currentBindingID (null if there is no current // binding), we need this when we "continueBinding". currentBindingID = null; var propertyBindings:Array = proxy.getBindings([propertyName]); if ((propertyBindings != null) && (propertyBindings.length > 0)) { // Use the 1st binding address for the property. currentBindingID = propertyBindings[0]; }
// Store the name of the property that we are binding, // we need this when we "continueBinding". propertyToBind = propertyName;
// Let the user choose where to bind to in the Excel spreadsheet. proxy.requestUserSelection(currentBindingID); }
/* ----------------------------------------------------------------------------- Completes the binding when the user has finished selecting the cell to bind to or cleared the binding ----------------------------------------------------------------------------- */ protected function continueBind(bindingID:String):void { var propertyName:String = propertyToBind; var propertyValues:Array; var propertyObject:Object; var bindingAddresses:Array;
// Clear any existing bindings - so we can re-bind. if (currentBindingID != null) { proxy.unbind(currentBindingID); currentBindingID = null; }
// Process the property binding. switch (propertyName) { case "visibleStatus": if ((bindingID == null) || (bindingID == "")){ statustext.text = null; proxy.setProperty(propertyName, null); proxy.setProperty("dynamicVisibility", false);
visiblelabel.enabled=false; keylabel.enabled=false; keytext.enabled=false; keybind.enabled=false;
return; } statustext.text = proxy.getBindingDisplayName(bindingID); if(statustext.text!=null){ visiblelabel.enabled=true; keylabel.enabled=true; keytext.enabled=true; keybind.enabled=true; } else{ visiblelabel.enabled=false; keylabel.enabled=false; keytext.enabled=false; keybind.enabled=false; } proxy.bind("visibleStatus", null, bindingID, BindingDirection.OUTPUT, "", OutputBindings.SINGLETON); proxy.setProperty("dynamicVisibility", true); break; case "visibleKey": if ((bindingID == null) || (bindingID == "")){ keytext.text = null; proxy.setProperty(propertyName, null); return; } keytext.text = proxy.getBindingDisplayName(bindingID); proxy.bind("visibleKey", null, bindingID, BindingDirection.OUTPUT, "", OutputBindings.SINGLETON); break; case "state": if ((bindingID == null) || (bindingID == "")){ stateInsertion.text =null; return; } stateInsertion.text = proxy.getBindingDisplayName(bindingID); proxy.bind("state", null, bindingID, BindingDirection.INPUT, InputBindings.SINGLETON, ""); break; default: break; } }
]]> </mx:Script>
<mx:ViewStack id="viewstack1" creationPolicy="all" left="0" right="0" y="51" height="100%" minWidth="268" minHeight="350">
<mx:Canvas id="general" label="General" minWidth="268" minHeight="350" width="100%" height="100%">
<!-- ~~~~~~~~~~~~Data Insertion section~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <mx:Label y="20" text="Data Insertion" width="145" left="23" fontWeight="bold"/> <mx:HRule y="29" right="56" left="110"/> <mx:Label text="Insert State (ON/OFF)" left="25" y="51"/> <mx:TextInput id="stateInsertion" y="50" right="83" left="150" enabled="false" /> <mx:Button y="51" right="56" width="24" click="initiateBind('state');" icon="@Embed('resources/bind to cell.png')"/>
</mx:Canvas>
<mx:Canvas id="behavior" label="Behavior" minWidth="268" minHeight="350" width="100%" height="100%">
<!-- ~~~~~~~~~~~~Default State section~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <mx:Label y="9" text="State" width="145" left="23" fontWeight="bold"/> <mx:HRule y="18" right="56" left="60"/> <mx:Label x="50" y="38" text="Default State"/> <mx:ComboBox dataProvider="{_state}" x="126" y="39" editable="false" width="73" id="defaultstate" change="{ proxy.setProperty('defaultState',defaultstate.selectedLabel); }"> </mx:ComboBox>
<!-- ~~~~~~~~~~~~Dynamic Visibility section~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <mx:Label y="88" text="Dynamic Visibility" width="145" left="23" fontWeight="bold"/> <mx:HRule y="97" right="56" left="128"/> <mx:Label y="115" text="Show component only if status matches key:" width="290" id="visiblelabel" enabled="false" left="50"/> <mx:Label x="69" y="144" text="Status:"/> <mx:TextInput id="statustext" x="126" y="144" width="77" enabled="false" change="{ proxy.setProperty('visibleStatus',statustext.text); if(statustext.text!=null){ visiblelabel.enabled=true; keylabel.enabled=true; keytext.enabled=true; keybind.enabled=true; } else{ visiblelabel.enabled=false; keylabel.enabled=false; keytext.enabled=false; keybind.enabled=false; } }"/> <mx:Button id="statusbind" y="144" width="24" click="initiateBind('visibleStatus');" icon="@Embed('resources/bind to cell.png')" x="206"/> <mx:Label id="keylabel" enabled="false" x="69" y="174" text="Key:"/> <mx:TextInput id="keytext" x="126" y="174" width="77" enabled="false" change="{ proxy.setProperty('visibleKey',keytext.text); var propertyBindings:Array = proxy.getBindings(['visibleKey']); var bId:String=propertyBindings[0]; proxy.unbind(bId); }"/> <mx:Button id="keybind" enabled="false" y="174" width="24" click="initiateBind('visibleKey');" icon="@Embed('resources/bind to cell.png')" x="206" height="23"/> </mx:Canvas>
</mx:ViewStack> <mx:TabBar x="0" y="0" dataProvider="{viewstack1}" height="51" width="209" fontWeight="bold" chromeColor="#1977CE" color="#FFFFFF"> </mx:TabBar> </mx:Application> |
5. Under src folder, create a new folder and name it resources. Locate the image file bind to cell.png in the location <Dashboards_Installation_Dir>\Xcelsius 4.0\SDK\samples\CustomPropSheetHorizontalSlider\CustomPropSheetHorizontalSliderPropertySheet\src\resources and copy it inside newly created resources folder.
6. Save all files and click File > Export Release Build...
7. We have successfully created the component and its property sheet.
1. Launch Dashboards Add-On Packager.
2. Give the name as OnOffButton.
3. Under Visual Components, Click Add Component.
4. Under Class Name, provide com.yahoo.ari007_cse.OnOffButton. Give the Display Name as OnOffButton. Browse Component SWF from <OnOffButton_Project_Location>\bin-release\OnOffButton.swf. Browse Property Sheet SWF from <OnOffButtonPropertySheet_Project_Location>\bin-release\OnOffButton.swf. Select a Category. The add-on will be available under this specified category in Dashboards Designer. Optionally, you can specify icons and version of the add-on.
5. Go to Build tab and Click Build Package button. Save the add-on as OnOffButton.xlx.
6. Install the add-on in Dashboards designer and test.
Happy dashboarding ... ![]()
Here, I shall describe how to create a Blinking Label custom component for SAP BusinessObjects Dashboards 4.0 SP3 or higher.
This is a custom Label component which can blink if a given condition is true. It is also possible to change the blinking frequency. We can set different text colors for blinking and non-blinking states.
The property sheet for this component has three tabs : General, Behavior and Appearance.
In this tab, we can mention the text of the label. We can either enter the value manually, or we can bind it to a cell in the excel model.
In this section, we can set the blink condition and the dynamic visibility for the label.
The slider to set a Blink Interval is enabled only when we bind the blink Status to a cell in the excel model.
In this tab, we can change various formatting options for the label text. Also, we can specify a different text color when the blink condition is true.
To create this add-on, I have used Adobe Flash Builder 4.0.1 with Adobe Flex SDK 4.0.0 build 14159.
The steps are described below :
1. Create a new project selecting File > New > Flex Project.
2. Give the project name as BlinkingText. Under Flex SDK version, select Flex 4.0. Click Finish.
3. Select the new project. Go to Project > Properties.
4. Under Flex Compiler section, apply the following command in Additional compiler arguments:
-locale=en_US -isolate-styles=false
5. Expand the project. Right click on src folder and create new Package with name com.yahoo.ari007_cse. This is the package I have used. You can give your own package name, but then you have to modify the codes accordingly.
6. Right click on the new package and create a new Actionscript File with name BlinkingText.
7. Open the newly created actionscript file and paste the code below :
BlinkingText.as |
|---|
/* ------------------------------------------------------------------ ActionScript file: BlinkingText.as Author: Arijit Das Date Created: Jan 17, 2013 ------------------------------------------------------------------ */
package com.yahoo.ari007_cse { import flash.events.Event; import flash.events.TimerEvent; import flash.utils.Timer;
import mx.containers.HBox; import mx.controls.Label; import mx.events.FlexEvent; import mx.styles.CSSStyleDeclaration; import mx.styles.StyleManager;
public class BlinkingText extends HBox{ /* ------------------------------------------------------------------ Properties ------------------------------------------------------------------ */ private var _label:Label=new Label(); private var _timer:Timer=new Timer(1000,0);
private var _text:String="Label"; private var _textChanged:Boolean=true; private var _timerInterval:uint=1000; private var _timerIntervalChanged:Boolean=true; private var _dynamicVisibility:Boolean=false; private var _visibleStatus:String=null; private var _visibleKey:String=null; private var _visibleKeyChanged:Boolean=false; private var _visibleStatusChanged:Boolean=true; private var _blinkStatus:String=null; private var _blinkStatusChanged:Boolean=true; private var _blinkKey:String=null; private var _blinkKeyChanged:Boolean=true; private var _blinkFlag:Boolean=false; private var _textColor:uint=0x000000; private var _fontFamily:String="Verdana"; private var _fontFamilyChanged:Boolean=true; private var _fontSize:int=10; private var _fontSizeChanged:Boolean=true; private var _fontWeight:String="normal"; private var _fontWeightChanged:Boolean=true; private var _fontStyle:String="normal"; private var _fontStyleChanged:Boolean=true; private var _textDecoration:String="none"; private var _textDecorationChanged:Boolean=true; private var _textAlign:String="left"; private var _textAlignChanged:Boolean=true; private var _blinkColor:uint=0xFF0000;
/* ------------------------------------------------------------------ Constructor ------------------------------------------------------------------ */ public function BlinkingText():void{ super(); } /* ------------------------------------------------------------------ Static Function to determine if the component is being used at design time ------------------------------------------------------------------ */ public static function isInCanvas():Boolean{ var globalStyle:CSSStyleDeclaration=StyleManager.getStyleManager(null).getStyleDeclaration("global"); if (Boolean(globalStyle.getStyle("inCanvas"))==true){ return true; } return false; } /* ------------------------------------------------------------------ Blink the Label ------------------------------------------------------------------ */ public function toggleText(event:TimerEvent):void{ if(this._label.visible) this._label.visible=false; else this._label.visible=true; } /* ------------------------------------------------------------------ When component is created, set visibility depending on property values ------------------------------------------------------------------ */ public function cretionCompleteHandler(event:Event):void{ if(!(_dynamicVisibility) || _visibleStatus==visibleKey || (_visibleStatus==null && visibleKey=="")){ this.visible=true; } else this.visible=false; } /* ------------------------------------------------------------------ labelText Property ------------------------------------------------------------------ */ public function get labelText():String{ return _text; } public function set labelText(labelText:String):void{ _text=labelText; _textChanged=true; invalidateProperties(); } /* ------------------------------------------------------------------ timerInterval Property ------------------------------------------------------------------ */ public function get timerInterval():uint{ return _timerInterval; } public function set timerInterval(interval:uint):void{ _timerInterval=interval; _timerIntervalChanged=true; invalidateProperties(); } /* ------------------------------------------------------------------ visibleKey Property ------------------------------------------------------------------ */ public function set visibleKey(key:String):void{ _visibleKey=key; _visibleKeyChanged=true; invalidateProperties(); } public function get visibleKey():String{ return _visibleKey; } /* ------------------------------------------------------------------ visibleStatus Property ------------------------------------------------------------------ */ public function set visibleStatus(status:String):void{ _visibleStatus=status; _visibleStatusChanged=true; invalidateProperties(); } public function get visibleStatus():String{ return _visibleStatus; } /* ------------------------------------------------------------------ dynamicVisibility Property ------------------------------------------------------------------ */ public function set dynamicVisibility(flag:Boolean):void{ _dynamicVisibility=flag; } public function get dynamicVisibility():Boolean{ return _dynamicVisibility; } /* ------------------------------------------------------------------ blinkKey Property ------------------------------------------------------------------ */ public function set blinkKey(key:String):void{ _blinkKey=key; _blinkKeyChanged=true; invalidateProperties(); } public function get blinkKey():String{ return _blinkKey; } /* ------------------------------------------------------------------ blinkStatus Property ------------------------------------------------------------------ */ public function set blinkStatus(status:String):void{ _blinkStatus=status; _blinkStatusChanged=true; invalidateProperties(); } public function get blinkStatus():String{ return _blinkStatus; } /* ------------------------------------------------------------------ blink Property ------------------------------------------------------------------ */ public function set blink(flag:Boolean):void{ _blinkFlag=flag; } public function get blink():Boolean{ return _blinkFlag; } /* ------------------------------------------------------------------ textColor Property ------------------------------------------------------------------ */ public function set textColor(color:uint):void{ _textColor=color; } public function get textColor():uint{ return _textColor; } /* ------------------------------------------------------------------ blinkColor Property ------------------------------------------------------------------ */ public function set blinkColor(bcolor:uint):void{ _blinkColor=bcolor; } public function get blinkColor():uint{ return _blinkColor; } /* ------------------------------------------------------------------ fontFamily Property ------------------------------------------------------------------ */ public function set fontFamily(font:String):void{ _fontFamily=font; _fontFamilyChanged=true; invalidateProperties(); } public function get fontFamily():String{ return _fontFamily; } /* ------------------------------------------------------------------ fontSize Property ------------------------------------------------------------------ */ public function set fontSize(size:int):void{ _fontSize=size; _fontSizeChanged=true; invalidateProperties(); } public function get fontSize():int{ return _fontSize; } /* ------------------------------------------------------------------ fontWeight Property ------------------------------------------------------------------ */ public function set fontWeight(weight:String):void{ _fontWeight=weight; _fontWeightChanged=true; invalidateProperties(); } public function get fontWeight():String{ return _fontWeight; } /* ------------------------------------------------------------------ fontStyle Property ------------------------------------------------------------------ */ public function set fontStyle(style:String):void{ _fontStyle=style; _fontStyleChanged=true; invalidateProperties(); } public function get fontStyle():String{ return _fontStyle; } /* ------------------------------------------------------------------ textDecoration Property ------------------------------------------------------------------ */ public function set textDecoration(decor:String):void{ _textDecoration=decor; _textDecorationChanged=true; invalidateProperties(); } public function get textDecoration():String{ return _textDecoration; } /* ------------------------------------------------------------------ textAlign Property ------------------------------------------------------------------ */ public function set textAlign(align:String):void{ _textAlign=align; _textAlignChanged=true; invalidateProperties(); } public function get textAlign():String{ return _textAlign; }
/* ------------------------------------------------------------------ Build composite component ------------------------------------------------------------------ */ override protected function createChildren():void{ super.createChildren(); this._label.text="Label"; this.addChild(_label); this._timer=new Timer(1000,0); this._timer.addEventListener(TimerEvent.TIMER,toggleText); this.minWidth=10; this.minHeight=10; this.addEventListener(FlexEvent.CREATION_COMPLETE,cretionCompleteHandler); }
/* ------------------------------------------------------------------ Action taken after change in any property ------------------------------------------------------------------ */ override protected function commitProperties():void{ super.commitProperties(); /* ------------------------------------------------------------------- Check whether to update the label text ------------------------------------------------------------------- */ if (this._textChanged) { this._label.text=_text; invalidateDisplayList(); _textChanged=false; } /* ------------------------------------------------------------------- Check whether to update the blink frequency ------------------------------------------------------------------- */ if (this._timerIntervalChanged) { this._timer.delay=_timerInterval; invalidateDisplayList(); _timerIntervalChanged=false; } /* ------------------------------------------------------------------- Check whether to show/hide the component ------------------------------------------------------------------- */ if(this._visibleKeyChanged || this._visibleStatusChanged){ if(!isInCanvas()){ if(!(_dynamicVisibility) || _visibleStatus==_visibleKey || (_visibleStatus==null && _visibleKey=="")){ this.visible=true; } else this.visible=false; invalidateDisplayList(); } _visibleKeyChanged=false; _visibleStatusChanged=false; } /* ------------------------------------------------------------------- Check whether to start/stop blinking the component ------------------------------------------------------------------- */ if(this._blinkKeyChanged || this._blinkStatusChanged){ if(_blinkFlag && ((_blinkStatus==_blinkKey) || (_blinkStatus==null && _blinkKey==""))){ this._timer.reset(); this._label.setStyle("color",_blinkColor); this._timer.start(); } else{ this._timer.reset(); this._label.visible=true; this._label.setStyle("color",_textColor); } invalidateDisplayList(); _blinkKeyChanged=false; _blinkStatusChanged=false; } /* ------------------------------------------------------------------- Check whether to update the label font ------------------------------------------------------------------- */ if (this._fontFamilyChanged) { this._label.setStyle("fontFamily",_fontFamily); invalidateDisplayList(); _fontFamilyChanged=false; } /* ------------------------------------------------------------------- Check whether to update the font size ------------------------------------------------------------------- */ if (this._fontSizeChanged) { this._label.setStyle("fontSize",_fontSize); invalidateDisplayList(); _fontSizeChanged=false; } /* ------------------------------------------------------------------- Check whether to update the font weight ------------------------------------------------------------------- */ if (this._fontWeightChanged) { this._label.setStyle("fontWeight",_fontWeight); invalidateDisplayList(); _fontWeightChanged=false; } /* ------------------------------------------------------------------- Check whether to update the font style ------------------------------------------------------------------- */ if (this._fontStyleChanged) { this._label.setStyle("fontStyle",_fontStyle); invalidateDisplayList(); _fontStyleChanged=false; } /* ------------------------------------------------------------------- Check whether to update the text decoration ------------------------------------------------------------------- */ if (this._textDecorationChanged) { this._label.setStyle("textDecoration",_textDecoration); invalidateDisplayList(); _textDecorationChanged=false; } /* ------------------------------------------------------------------- Check whether to update the text alignment ------------------------------------------------------------------- */ if (this._textAlignChanged) { this.setStyle("horizontalAlign",_textAlign); invalidateDisplayList(); _textAlignChanged=false; } }
} } |
8. Open BlinkingText.mxml file under the default package and paste the code below :
| BlinkingText.mxml |
|---|
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:ns="com.yahoo.ari007_cse.*"> <ns:BlinkingText height="100%" width="100%"/> </s:Application> |
9. Save the files and click on Export Release Build button. The same can also be done from File > Export > Release Build.
10. In the next screen, click Finish.
1. Create a new Flex Project as earlier with name BlinkingTextPropertySheet.
2. Go to project properties. Under Flex Build path, click on Add SWC... and browse to the file xcelsiusframework.swc located in <Dashboards_Installation_Dir>\Xcelsius 4.0\SDK\bin.
3. Under Flex Compiler section, apply the following command in Additional compiler arguments:
-locale=en_US -isolate-styles=false
4. Under src folder, create a new folder and name it resources. Locate the image file bind to cell.png in the location <Dashboards_Installation_Dir>\Xcelsius 4.0\SDK\samples\CustomPropSheetHorizontalSlider\CustomPropSheetHorizontalSliderPropertySheet\src\resources and copy it inside newly created resources folder.
5. Open the file BlinkingTextPropertySheet.mxml under default package and paste the code below :
| BlinkingTextPropertySheet.mxml |
|---|
<?xml version="1.0" encoding="utf-8"?>
<!-- File Name: BlinkingTextPropertySheet.mxml Author: Arijit Das Date Created: Jan 17, 2013 -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="init();" backgroundColor="#F7F9FC" backgroundAlpha="1.0" preloaderChromeColor="#FEFEFF">
<mx:Script> <![CDATA[ import mx.containers.*; import mx.controls.*; import mx.core.Container; import mx.events.FlexEvent;
import xcelsius.binding.BindingDirection; import xcelsius.binding.tableMaps.input.InputBindings; import xcelsius.binding.tableMaps.output.OutputBindings; import xcelsius.propertySheets.impl.PropertySheetExternalProxy; import xcelsius.propertySheets.interfaces.IPropertySheetProxy; import xcelsius.propertySheets.interfaces.PropertySheetFunctionNamesSDK;
/* ----------------------------------------------------------------------------- The Xcelsius proxy between this Property Sheet and its Xcelsius custom component. ----------------------------------------------------------------------------- */ protected var proxy:IPropertySheetProxy = new PropertySheetExternalProxy(); /* ----------------------------------------------------------------------------- The name of the property that the user is (re-)binding. ----------------------------------------------------------------------------- */ protected var propertyToBind:String; /* ----------------------------------------------------------------------------- The current binding id (may be null if there is no binding) for the property the user is (re)-binding. ----------------------------------------------------------------------------- */ protected var currentBindingID:String; /* ----------------------------------------------------------------------------- The system fonts that the user can choose from. ----------------------------------------------------------------------------- */ [Bindable] private var _fontNames:Array = []; /* ----------------------------------------------------------------------------- The list of selectable font sizes. ----------------------------------------------------------------------------- */ [Bindable] protected var _fontSizes:Array = new Array("8", "9", "10", "11", "12", "14", "16", "18", "20", "22");
/* ----------------------------------------------------------------------------- Initialises this Property Sheet on load. ----------------------------------------------------------------------------- */ protected function init():void { proxy.addCallback(PropertySheetFunctionNamesSDK.GET_PROPERTIES_FUNCTION, getProperties); proxy.addCallback(PropertySheetFunctionNamesSDK.RESPONSE_BINDING_ID, this.continueBind); proxy.callContainer(PropertySheetFunctionNamesSDK.INIT_COMPLETE_FUNCTION);
// Fill-in the list of system fonts. var allFonts:Array = Font.enumerateFonts(true); // retrieve the list of fonts on the current machine allFonts.sortOn("fontName", Array.CASEINSENSITIVE); var numFonts:int = allFonts.length; for (var i:int=0; i<numFonts; i++) { var font:Font = allFonts[i]; // copy fonts into dataProvider for ComboBox _fontNames.push(font.fontName); }
loadProperties(); initValues(); }
protected function getProperties():Array { var persist:Array = new Array(); var persistObject:Object = new Object(); persistObject.name = "selectedTab"; persistObject.value = viewstack1.selectedIndex; persist.push(persistObject);
return persist; }
/* ----------------------------------------------------------------------------- Load the selected tab ----------------------------------------------------------------------------- */ protected function loadProperties():void { var persistProperties:Array = proxy.getPersist(["selectedTab"]); if (persistProperties != null && persistProperties.length != 0) { var propertyObject:Object = persistProperties[0]; var propertyValue:* = propertyObject.value; viewstack1.selectedIndex = propertyValue as int; } }
/* ----------------------------------------------------------------------------- Initialises this Property Sheet on load to show the current Xcelsius custom component property/style value ----------------------------------------------------------------------------- */ protected function initValues():void { var propertyValues:Array = proxy.getProperties([ "labelText", "timerInterval", "visibleKey", "visibleStatus", "blinkKey", "blinkStatus", "textColor", "blinkColor", "fontFamily", "fontSize", "fontWeight", "fontStyle", "textDecoration", "textAlign" ]);
var propertyValuesLength:int = (propertyValues != null ? propertyValues.length : 0); for (var i:int=0; i < propertyValuesLength; i++) { var propertyObject:Object = propertyValues[i]; var propertyName:String = propertyObject.name; var propertyValue:* = propertyObject.value; var bindingText:String = ""; switch (propertyName) { case "labelText": bindingText = getPropertyBindDisplayName(propertyName); if (bindingText != null){ textEditor.text = bindingText; } else textEditor.text = propertyValue; break; case "timerInterval": blinkinterval.value=propertyValue; break; case "visibleStatus": bindingText = getPropertyBindDisplayName(propertyName); if (bindingText != null){ statustext.text = bindingText; visiblelabel.enabled=true; keylabel.enabled=true; keytext.enabled=true; keybind.enabled=true; } else { visiblelabel.enabled=false; keylabel.enabled=false; keytext.enabled=false; keybind.enabled=false; } break; case "visibleKey": bindingText = getPropertyBindDisplayName(propertyName); if (bindingText != null){ keytext.text = bindingText; } else keytext.text = propertyValue; break; case "blinkStatus": bindingText = getPropertyBindDisplayName(propertyName); if (bindingText != null){ blinkstatustext.text = bindingText; blinkconditionlabel.enabled=true; blinkkeylabel.enabled=true; blinkkeytext.enabled=true; blinkkeybind.enabled=true; blinkintervallabel.enabled=true; blinkinterval.enabled=true; } else { blinkconditionlabel.enabled=false; blinkkeylabel.enabled=false; blinkkeytext.enabled=false; blinkkeybind.enabled=false; blinkintervallabel.enabled=false; blinkinterval.enabled=false; } break; case "blinkKey": bindingText = getPropertyBindDisplayName(propertyName); if (bindingText != null){ blinkkeytext.text = bindingText; } else blinkkeytext.text = propertyValue; break; case "textColor": color.selectedColor=propertyValue; break; case "blinkColor": blinkcolor.selectedColor=propertyValue; break; case "fontFamily": fontfamily.selectedIndex=_fontNames.indexOf(propertyValue); break; case "fontSize": fontsize.selectedIndex=_fontSizes.indexOf(String(propertyValue)); break; case "fontWeight": bold.selected=(propertyValue=="bold"); break; case "fontStyle": italic.selected=(propertyValue=="italic"); break; case "textDecoration": underline.selected=(propertyValue=="underline"); break; case "textAlign": if(propertyValue=="left")left.selected=true; else if(propertyValue=="right")right.selected=true; else center.selected=true; break; default: break; } } }
/* ----------------------------------------------------------------------------- Returns the bind display name or null if not bound ----------------------------------------------------------------------------- */ protected function getPropertyBindDisplayName(propertyName:String):String { // Get the array of bindings for this property. var propertyBindings:Array = proxy.getBindings([propertyName]); if ((propertyBindings != null) && (propertyBindings.length > 0) && (propertyBindings[0].length > 0)) { // We have at least one binding for this property so pick the 1st one. // Note: [0][0] is 1st property in the array, then 1st binding for that property. var bindingID:String = propertyBindings[0][0]; return proxy.getBindingDisplayName(bindingID); } return null; }
/* ----------------------------------------------------------------------------- Allows the user to select the Excel spreadsheet cell to bind to an Xcelsius custom component property ----------------------------------------------------------------------------- */ protected function initiateBind(propertyName:String):void { // If there is an existing binding for this property show // that in the Excel binding selection window. // Store the currentBindingID (null if there is no current // binding), we need this when we "continueBinding". currentBindingID = null; var propertyBindings:Array = proxy.getBindings([propertyName]); if ((propertyBindings != null) && (propertyBindings.length > 0)) { // Use the 1st binding address for the property. currentBindingID = propertyBindings[0]; }
// Store the name of the property that we are binding, // we need this when we "continueBinding". propertyToBind = propertyName;
// Let the user choose where to bind to in the Excel spreadsheet. proxy.requestUserSelection(currentBindingID); }
/* ----------------------------------------------------------------------------- Completes the binding when the user has finished selecting the cell to bind to or cleared the binding ----------------------------------------------------------------------------- */ protected function continueBind(bindingID:String):void { // Define common variables here. var propertyName:String = propertyToBind; var propertyValues:Array; var propertyObject:Object; var bindingAddresses:Array;
// Clear any existing bindings - so we can re-bind. if (currentBindingID != null) { proxy.unbind(currentBindingID); currentBindingID = null; }
// Process the property binding. switch (propertyName) { case "labelText": if ((bindingID == null) || (bindingID == "")){ propertyValues = proxy.getProperties([propertyName]); propertyObject = propertyValues[0]; textEditor.text = String(propertyObject.value);
proxy.setProperty(propertyName, propertyObject.value); return; }
textEditor.text = proxy.getBindingDisplayName(bindingID);
proxy.bind("labelText", null, bindingID, BindingDirection.OUTPUT, "", OutputBindings.SINGLETON); break; case "visibleStatus": if ((bindingID == null) || (bindingID == "")){ statustext.text = null; proxy.setProperty(propertyName, null); proxy.setProperty("dynamicVisibility", false);
visiblelabel.enabled=false; keylabel.enabled=false; keytext.enabled=false; keybind.enabled=false;
return; } statustext.text = proxy.getBindingDisplayName(bindingID); if(statustext.text!=null){ visiblelabel.enabled=true; keylabel.enabled=true; keytext.enabled=true; keybind.enabled=true; } else{ visiblelabel.enabled=false; keylabel.enabled=false; keytext.enabled=false; keybind.enabled=false; } proxy.bind("visibleStatus", null, bindingID, BindingDirection.OUTPUT, "", OutputBindings.SINGLETON); proxy.setProperty("dynamicVisibility", true); break; case "visibleKey": if ((bindingID == null) || (bindingID == "")){ keytext.text = null; proxy.setProperty(propertyName, null); return; }
keytext.text = proxy.getBindingDisplayName(bindingID);
proxy.bind("visibleKey", null, bindingID, BindingDirection.OUTPUT, "", OutputBindings.SINGLETON); break; case "blinkStatus": if ((bindingID == null) || (bindingID == "")){ blinkstatustext.text = null; proxy.setProperty(propertyName, null); proxy.setProperty("blink", false);
blinkconditionlabel.enabled=false; blinkkeylabel.enabled=false; blinkkeytext.enabled=false; blinkkeybind.enabled=false; blinkintervallabel.enabled=false; blinkinterval.enabled=false;
return; } blinkstatustext.text = proxy.getBindingDisplayName(bindingID); if(blinkstatustext.text!=null){ blinkconditionlabel.enabled=true; blinkkeylabel.enabled=true; blinkkeytext.enabled=true; blinkkeybind.enabled=true; blinkintervallabel.enabled=true; blinkinterval.enabled=true; } else{ blinkconditionlabel.enabled=false; blinkkeylabel.enabled=false; blinkkeytext.enabled=false; blinkkeybind.enabled=false; blinkintervallabel.enabled=false; blinkinterval.enabled=false; } proxy.bind("blinkStatus", null, bindingID, BindingDirection.OUTPUT, "", OutputBindings.SINGLETON); proxy.setProperty("blink", true); break; case "blinkKey": if ((bindingID == null) || (bindingID == "")){ blinkkeytext.text = null; proxy.setProperty(propertyName, null); return; }
blinkkeytext.text = proxy.getBindingDisplayName(bindingID);
proxy.bind("blinkKey", null, bindingID, BindingDirection.OUTPUT, "", OutputBindings.SINGLETON); break; default: break; } }
]]> </mx:Script>
<mx:ViewStack id="viewstack1" creationPolicy="all" left="0" right="0" y="51" height="100%" minWidth="268" minHeight="350"> <mx:Canvas id="general" label="General" minWidth="268" minHeight="350" width="100%" height="100%"> <!-- ~~~~~~~~~~~~Label Text section~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <mx:Label y="8" text="Text" width="40" left="23" fontWeight="bold"/> <mx:HRule y="17" right="56" left="55"/> <mx:TextInput id="textEditor" y="36" right="83" left="35" change="{ proxy.setProperty('labelText',textEditor.text); var propertyBindings:Array = proxy.getBindings(['labelText']); var bId:String=propertyBindings[0]; proxy.unbind(bId); }"/> <mx:Button y="35" right="56" width="24" click="initiateBind('labelText');" icon="@Embed('resources/bind to cell.png')" height="24"/> </mx:Canvas>
<mx:Canvas id="behavior" label="Behavior" minWidth="268" minHeight="350" width="100%" height="100%"> <!-- ~~~~~~~~~~~~Blinking Condition section~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <mx:Label y="8" text="Blink" width="119" left="23" fontWeight="bold"/> <mx:HRule y="17" right="56" left="55"/>
<mx:Label y="35" text="Blink component only if status matches key:" width="297" id="blinkconditionlabel" enabled="false" left="50"/>
<mx:Label x="69" y="64" text="Status:"/> <mx:TextInput id="blinkstatustext" x="126" y="64" width="77" enabled="false" change="{ proxy.setProperty('blinkStatus',blinkstatustext.text); if(blinkstatustext.text!=null){ blinkconditionlabel.enabled=true; blinkkeylabel.enabled=true; blinkkeytext.enabled=true; blinkkeybind.enabled=true; blinkintervallabel.enabled=true; blinkinterval.enabled=true; } else{ blinkconditionlabel.enabled=false; blinkkeylabel.enabled=false; blinkkeytext.enabled=false; blinkkeybind.enabled=false; blinkintervallabel.enabled=false; blinkinterval.enabled=false; } }"/> <mx:Button id="blinkstatusbind" y="63" width="24" click="initiateBind('blinkStatus');" icon="@Embed('resources/bind to cell.png')" x="206" height="22"/> <mx:Label id="blinkkeylabel" enabled="false" x="69" y="94" text="Key:"/> <mx:TextInput id="blinkkeytext" x="126" y="94" width="77" enabled="false" change="{ proxy.setProperty('blinkKey',blinkkeytext.text); var propertyBindings:Array = proxy.getBindings(['blinkKey']); var bId:String=propertyBindings[0]; proxy.unbind(bId); }"/> <mx:Button id="blinkkeybind" enabled="false" y="94" width="24" click="initiateBind('blinkKey');" icon="@Embed('resources/bind to cell.png')" x="206"/>
<!-- ~~~~~~~~~~~~Blinking Frequency section~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <mx:Label y="137" text="Blink Interval (in ms)" width="229" left="50" id="blinkintervallabel" enabled="false"/> <mx:HSlider y="164" left="50" right="83" id="blinkinterval" enabled="false" labels="[500,1000,1500,2000]" tickInterval="100" snapInterval="50" value="1000" maximum="2000" minimum="500" showDataTip="true" change="{ proxy.setProperty('timerInterval',blinkinterval.value); }" />
<!-- ~~~~~~~~~~~~Dynamic Visibility section~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <mx:Label y="234" text="Dynamic Visibility" width="145" left="23" fontWeight="bold"/> <mx:HRule y="243" right="56" left="128"/> <mx:Label y="261" text="Show component only if status matches key:" width="290" id="visiblelabel" enabled="false" left="50"/> <mx:Label x="69" y="290" text="Status:"/> <mx:TextInput id="statustext" x="126" y="290" width="77" enabled="false" change="{ proxy.setProperty('visibleStatus',statustext.text); if(statustext.text!=null){ visiblelabel.enabled=true; keylabel.enabled=true; keytext.enabled=true; keybind.enabled=true; } else{ visiblelabel.enabled=false; keylabel.enabled=false; keytext.enabled=false; keybind.enabled=false; } }"/> <mx:Button id="statusbind" y="290" width="24" click="initiateBind('visibleStatus');" icon="@Embed('resources/bind to cell.png')" x="206"/> <mx:Label id="keylabel" enabled="false" x="69" y="320" text="Key:"/> <mx:TextInput id="keytext" x="126" y="320" width="77" enabled="false" change="{ proxy.setProperty('visibleKey',keytext.text); var propertyBindings:Array = proxy.getBindings(['visibleKey']); var bId:String=propertyBindings[0]; proxy.unbind(bId); }"/> <mx:Button id="keybind" enabled="false" y="320" width="24" click="initiateBind('visibleKey');" icon="@Embed('resources/bind to cell.png')" x="206" height="23"/> </mx:Canvas> <mx:Canvas label="Appearance" width="100%" height="100%"> <!-- ~~~~~~~~~~~~Text Formating section~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <mx:Label y="10" text="Format Selected Text" left="23" fontWeight="bold"/> <mx:HRule y="18" left="148" right="56"/> <mx:ComboBox id="fontfamily" dataProvider="{_fontNames}" y="37" width="247" left="50" change="{ proxy.setProperty('fontFamily',fontfamily.selectedLabel); }"/> <mx:ComboBox id="fontsize" dataProvider="{_fontSizes}" x="317" y="37" width="72" change="{ proxy.setProperty('fontSize',int(fontsize.value)); }"/> <mx:Button id="bold" y="77" label="B" width="25" left="50" toggle="true" change="{ proxy.setProperty('fontWeight',(bold.selected ? 'bold' : 'normal')); }"/> <mx:Button id="italic" x="83" y="77" label="I" width="25" fontStyle="italic" toggle="true" change="{ proxy.setProperty('fontStyle',(italic.selected ? 'italic' : 'normal')); }"/> <mx:Button id="underline" x="116" y="77" label="U" width="25" textDecoration="underline" toggle="true" change="{ proxy.setProperty('textDecoration',(underline.selected ? 'underline' : 'none')); }"/> <mx:RadioButtonGroup id="textalign"/> <mx:RadioButton id="left" x="170" y="81" label="Left" groupName="textalign" selected="true" change="{ if(left.selected)proxy.setProperty('textAlign','left'); }"/> <mx:RadioButton id="center" x="222" y="81" label="Center" groupName="textalign" change="{ if(center.selected)proxy.setProperty('textAlign','center'); }"/> <mx:RadioButton id="right" x="287" y="81" label="Right" groupName="textalign" change="{ if(right.selected)proxy.setProperty('textAlign','right'); }"/> <mx:ColorPicker id="color" x="367" y="77" change="{ proxy.setProperty('textColor',color.selectedColor); }"/> <mx:Label y="120" text="Blink Color" left="50"/> <mx:ColorPicker id="blinkcolor" x="119" y="117" color="0xFF0000" change="{ proxy.setProperty('blinkColor',blinkcolor.selectedColor); }"/> </mx:Canvas>
</mx:ViewStack> <mx:TabBar x="0" y="0" dataProvider="viewstack1" height="51" width="295" fontWeight="bold" chromeColor="#1977CE" color="#FFFFFF"> </mx:TabBar> </mx:Application> |
6. Save the file and click on File > Export > Release Build. Click Finish in the next screen.
We have already created the component and the property sheet. Now, this is our final step to create the add-on file.
1. Launch Dashboards Add-On Packager.
2. Give the name as BlinkingText.
3. Under Visual Components, Click Add Component.
4. Under Class Name, provide com.yahoo.ari007_cse.BlinkingText. Give the Display Name as BlinkingText. Browse Component SWF from <BlinkingText_Project_Location>\bin-release\BlinkingText.swf. Browse Property Sheet SWF from <BlinkingTextPropertySheet_Project_Location>\bin-release\BlinkingText.swf. Select a Category. The add-on will be available under this specified category in Dashboards Designer. Optionally, you can specify icons and version of the add-on.
** To find the project location, go to the project properties and under resource section, you can find the location.
5. Go to Build tab and Click Build Package button. Save the add-on as BlinkingText.xlx.
6. We have successfully created the add-on. Now it is time to test this in Dashboards.
Install the add-on from File > Manage Add-Ons... option in dashboards Designer. Find the newly installed component under the category we selected during packaging the add-on and drag it into the canvas. Now test the features and enjoy
.
You might think that is a fairly dramatic statement, but I would go further to say that there will come a point, in the near future, when interactive dashboards become the only BI capability organizations will use to deliver information to their end-users.
Just to be clear, in saying this, I am dividing people into two categories, “end-users” and “analysts”. Whilst there are some shades of grey between these two, the advantages of thinking about them separately far out-weigh the disadvantages (I will leave the dangerous idea that “everyone is an analyst these days”, for a future post).
Analysts are really quite easy to identify. Their business card has the work “analyst” written on it (or perhaps data scientist or something like that, but I think you get my point), and although they need access to dashboards as well, they also need more specialized data discovery and predicative tools.
However, if you don’t have “analyst” on your business card, or in your job title, then you are an end-user and, as I said, your entire BI needs can (and should) be delivered through interactive dashboards.
But, these are not the old generation of “a collection of grids and graphs” dashboards. No, these are a new generation of interactive dashboards which go well beyond simply providing an “at-a-glance overview”.
There are five key features which make interactive dashboards such a BI powerhouse :-
These, together with the ability to deliver dashboards to mobile devices (particularly tablets), turn dashboards into the “iPad-app-like” BI which end-users are coming to crave.
To learn more about these topics, to see how SAP Dashboards and Xcelsius can be used to quickly create interactive dashboards and to start to prepare for this brave new world of dashboard-based BI, watch the recorded webcast of “If you think you know dashboards, think again”.