Skip to Content

I decided to see what kind of a Frankenstein creation I could make work by parameterizing a DS Addon to drive an embedded SWF (Xcelsius, even) for fun.  This of course will fail miserably for mobile use cases, but maybe someone who had a very specific reason to embed a SWF in some sort of crazy way may find this useful.

Was this a bad idea?  Probably.  Was it funny to see work?  Yes.

Basically, my intent was to see if I could add a few sample parameters to a DS addon that would carry over to a SWF via Flash Variables.  Probably a better way to do this for more fluid or interactive interactions would have been implementing some of this using External Interface to the Flash runtime, but seeing as I’ll personally never use this addon for any productive use, I didn’t fully build that out, but anyone who uses the ExternalInterface connectivity for Xcelsius already knows enough JavaScript to figure that out, but I digress…

Similar to my last blog entry, I made some changes mostly to the contribution.xml and contribution.js files to implement this.  I chose the jQuery Tools framework to implement the Flash object embedding, but you could also use SWFTools or others, I’m sure.  This was the only JS Include I had to add to the contribution.xml file.  I did however also add a few properties, such as SWF URL, Chart Title, Chart Values, and Chart Labels:


<?xml version="1.0" encoding="UTF-8"?>
<sdkExtension xmlns="http://www.sap.com/bi/zen/sdk"
          id="com.ipaper.sample.xcelsiuswrapper"
          title="Xcelsius Wrapper Example"
          version="1.0"
          vendor="Mike Howles"
          >
          <component id="XcelsiusWrapper"
                    title="Xcelsius Wrapper"
                    icon="res/icon.png"
                    handlerType="div"
                    propertySheetPath="res/additional_properties_sheet/additional_properties_sheet.html">
                    <jsInclude>res/js/component.js</jsInclude>
                    <jsInclude>res/js/jquery.tools.min.js</jsInclude>
                    <cssInclude>res/css/component.css</cssInclude>
                    <property id="color" type="Color" title="Color" group="Display" />
                    <property id="swf" type="String" title="SWF URL" group="Display" />
                    <property id="title" type="String" title="Chart Title" group="Display" />
                    <property id="chartVals" type="String" title="Chart Values" group="Display" />
                    <property id="chartLabels" type="String" title="Chart Labels" group="Display" />
                    <initialization>
                              <defaultValue property="WIDTH">400</defaultValue>
                              <defaultValue property="HEIGHT">300</defaultValue>
                              <defaultValue property="title">Xcelsius Title</defaultValue>
                              <defaultValue property="chartVals">10,20,30,20,10</defaultValue>
                              <defaultValue property="chartLabels">Widgets, Gizmos, Cogs, Wheels, Spokes</defaultValue>
                    </initialization>
          </component>
</sdkExtension>

Next, I made some of these properties available to the pseudo JS language in the contribution.ztl file:


class com.ipaper.sample.xcelsiuswrapper.XcelsiusWrapper extends Component {
          /* Returns the current color of the box */
          String getTitle() {*
                    return this.title;
          *}
          /* Sets the chart title */
          void setTitle(/* the new title */ String newTitle) {*
                    this.title = newTitle;
          *}
          /* Returns the chart labels */
          String getLabels() {*
                    return this.chartLabels;
          *}
          /* Sets the chart labels */
          void setLabels(/* new chart labels */ String newLabels) {*
                    this.chartLabels = newLabels;
          *}
          /* Returns the chart values */
          String getValues() {*
                    return this.chartVals;
          *}
          /* Sets the chart values */
          void setValues(/* new chart values */ String newValues) {*
                    this.chartVals = newValues;
          *}
}

And finally, I implemented the JavaScript code to make all this work.  I did have to rely on some global declarations to track multiple SWF instances, and also due to the way that Xcelsius fires a setSWFISReady JS callback.  There’s probably a better way, but whatever.  It worked for this exercise.


// Global Xcelsius callback function
function setSWFIsReady(xlcID) {
          var ref = swfStatus.getInstanceById(xlcID);
          if(!ref) return;
          ref.loaded = true;
          // Issue callback notifying DS that Xcelsius SWF is loaded.
          ref.dsRef.swfLoaded();
}
// Singleton-type registry for Xcelsius callback tracking
var swfStatus = swfStatus || {
                    instances : [],
                    registerInstance : function(dsRef){
                              for(var i=0;i<this.instances.length;i++){
                                        if(this.instances[i].dsRef==dsRef) return this.instances[i];
                              }
                              var newRef = {
                                        dsRef : dsRef,
                                        id : "xlcsWrapper" + this.instances.length
                              };
                              this.instances.push(newRef);
                              return newRef;
                    },
                    getInstance : function(dsRef){
                              for(var i=0;i<this.instances.length;i++){
                                        if(this.instances[i].dsRef==dsRef) return this.instances[i];
                              }
                              return null;
                    },
                    getInstanceById : function(id){
                              for(var i=0;i<this.instances.length;i++){
                                        if(this.instances[i].id==id) return this.instances[i];
                              }
                              return null;
                    },
                    loaded:false,
                    id:null,
                    dsRef:null
};
sap.designstudio.sdk.Component.subclass("com.ipaper.sample.xcelsiuswrapper.XcelsiusWrapper", function() {
          var that = this;
          this.swfAPI = null;
          this._title = "";
          this._swf = "";
          this._chartVals = "";
          this._chartLabels = "";
          this.chartVals = function(value){
                    if(value!=undefined) {
                              this._chartVals = value;
                              this.redraw();
                    }
                    return this;
          };
          this.chartLabels = function(value){
                    if(value!=undefined) {
                              this._chartLabels = value;
                              this.redraw();
                    }
                    return this;
          };
          this.swf = function(value) {
                    if(value!=undefined) {
                              this._swf = value;
                              this.redraw();
                    }
                    return this;
          };
          this.title = function(value) {
                    if(value!=undefined) {
                              this._title = value;
                              this.redraw();
                    }
                    return this;
          };
    this.afterUpdate = function() {
              // alert("after update");
    };
          this.redraw = function(){
                    var regRef = swfStatus.registerInstance(this);
                    regRef.loaded = false;
                    this.swfAPI = this.$().flashembed({
                              src : this._swf,
                              id : regRef.id
                    },{
                              title : this._title,
                              chartVals : this._chartVals,
                              chartLabels : this._chartLabels
                    });
          };
    this.init = function() {
                    this.$().css("padding","5px");
                    this.redraw();
          };
          this.swfLoaded = function(){
                    // Xcelsius Loaded Callback
                    var swfID = swfStatus.getInstance(this).id;
                    var movie = document.getElementById(swfID);
                    // Insert Xcelsius External Interface API calls at this point, if I wanted.
          };
          this.color = function(value) {
                    if (value === undefined) {
                              return this.$().css("background-color");
                    } else {
                              this.$().css("background-color", value);
                              return this;
                    }
          };
});

The end-result was a configurable, and questionably-useful component that you can configure programatically in DS and the Properties pane:

/wp-content/uploads/2013/11/x1_333028.png

As you can see, after dropping in the wrapper, setting a SWF URL, and a few example properties mentioned above, you have an example of a SWF you can manipulate using Flash Vars.  Next, I added two buttons that just populate the component with different “datasets”

/wp-content/uploads/2013/11/x2_333041.png

And, at runtime, this is the result of clicking:

/wp-content/uploads/2013/11/x3_333042.png

For those of you who enjoy seeing the strange marriage between DS and Xcelsius, enjoy!  🙂

To report this post you need to login first.

1 Comment

You must be Logged on to comment or reply to a post.

Leave a Reply