Saturday, February 20, 2010

Doing Math with Strings in Actionscript, General Type Casting

     I have been getting some calls about addition not working with point values from Inetsupervisor. I have no way of knowing what type of value that will be sent to the connector so I assign conn.output as a string type so I can handle all form of data values. In AS2.0 most all values that are generic objects or just are not explicitly typed are implicitly cast to string. So if you need to do addition, and 1 or more object is a string then, explicitly type cast them to the Number.

Example:
a = status_txt.text + 15; //add the values of text box and 15. If the text is 1 but the all text is cast as string so a string concatenation will happen
trace(a);// value is 115. Bad


a = Number(status_txt.text) + 15; //add the values of text box and 15. The text value is still 1 but I have cast it to a number. 2 numbers will do math operations
trace(a);// value is 16. Good


    This is most common casting you will have to work with, but sometimes you need to insert a number to a string:

var num:Number = 5;
a = "Hello all " + String(num) + " of you"; //num is a typed as a number with the value of 5 so it needs a cast to do string concatenation
trace(a);// Hello all 5 of you. Good


    So since all values in AS are based as generic objects they all can be cast to some other type when needed.

Labels: , ,

Thursday, April 9, 2009

Flash Movie to send multiple, user defined values

Most of the time everybody works with the standard override values, ON - OFF or some setpoint value, but what if we need something more. What do you do if you made you own variable that does 3 or more functions. Plus what if we need to change the output based on the type of equipment. We will focus on a movie that has 3 buttons and will send a different user defined value depending on which button is clicked. In addition I will show you how to add and use EventListener's.

First start a new movie, drop a connector component and 3 buttons. Give everybody an instance name and assign the ID to the connector.

con.ID = PointID; // Assign the point ID to work with

Then we will add some code to change the button labels just incase the defaults don't jive with what we are tring to do.

//This runs to find if any params called names exist if it does then use it to change the names of the buttons
//names must be a comma delimited string of names
if (names != undefined){//param names exist
var button_names:Array = names.split(',');//split the string by comma's
button1.label = button_names[0];//assign first object
button2.label = button_names[1];//assign second object
button3.label = button_names[2];//assign third object
}

Now we need to make a variable to hold our output values then fill it up with some values

var output_values:Array = new Array();//create an array to hold the output values

If the prameter outputvalue exist then parse it and fill the array

if (outputvalue != undefined){
var outputValuesTmpArray:Array = outputvalue.split(',');
output_values[0] = outputValuesTmpArray[0];
output_values[1] = outputValuesTmpArray[1];
output_values[2] = outputValuesTmpArray[2];
}
else{//no user defined output values so assign some default values
output_values[0] = "0";
output_values[1] = "1";
output_values[2] = "2";
}

Your default values can be anything I would suggest your most common used values, so you don't have to override them as much.
Next all that is need is the code to send the value when the button is clicked.

button1.addEventListener("click",button1_listener);//create a listening function for the click event of button 1
function button1_listener(evt){
con.sendOverride(PointID,output_values[0]);//when button 1 is clicked send the 1st value of the output_value array
}

button2.addEventListener("click",button2_listener);//create a listening function for the click event of button 2
function button2_listener(evt){
con.sendOverride(PointID,output_values[1]);//when button 2 is clicked send the 2nd value of the output_value array
}

button3.addEventListener("click",button3_listener);//create a listening function for the click event of button 3
function button3_listener(evt){
con.sendOverride(PointID,output_values[2]);//when button 3 is clicked send the 3rd value of the output_value array
}

stop();//stop at this frame


Normally I would have you place the con.sendOverride function inside the button using the on(click) method and use the _parent scope, but I thought this would be a good opertunity to show you EventListeners. All objects(buttons, text, graphics...) fire events when they do things (mouse click|up|down|over, change,resize...) and if you what to do something when this happens you can attach a listener function to fire when the event happens. In the case of button1, we attached the function button1_listener to the "click" event, so when the "click" event fires button1_listener will "hear" it and then run. When the button1_listener function runs we send out the value of output_value[instance 0]. This can be used to make graphics into buttons or do something while typing...

Next just place the movie on your web page and set the PointID then names value with a comma delimited string (ie names=hand,off,auto) if you need, and do the same with outputvalue (ie outputvalue=ST_LOW,ST_MED,ST_HIGH or outputvalue=100.0 1,0.0 0,0.0 -1). If you need more then 3 options you can just add more buttons and use the next array value instance or maybe use a combobox or different type of UI to scale it up.

You can download the source and compiled here.

3_Button.rar

Labels: , ,

Friday, January 2, 2009

DreamweaverCS4 AC_FL_RunContent Script Compatibility

The CS4 version of DW does not support or use AC_FL_RunActiveContent script for flash movies anymore. If you remember This script was used to stop the ActiveX hash box in Internet Explorer 6 and 7. This had not been nessisary for IE since an update in the first part of 2008.

If you have made pages with DW8.02 or CS3 and have the "Insert Browser Safe Script" option check then you have seen this script generated. When (or if) you transfer to the CS4 version of Dreamweaver and you work with the older web pages the flash movies will not update any changes you will make. This is caused by the fact that the AC_FL_RunActiveContent script actually creates and loads the flash movie for you from javascript and CS4 does not update the information in the script as it does in the object, so when you load the movie only the old information is loaded. There are 2 options to fix this issue:
  1. Remove the script by hand
  2. Modify Dreamweaver to update the scripting
We will start with option 1. When looking at the flash movie in "code" design you will notice the object is wrapped in noscript tags. This is used to tell the browser not to generate the information inside of these tag's. So the only thing generated by the browser is the content created by the AC_FL_RunActiveContent script above it. When you modify the object tag, dreamweaver use to automatically match the script above it. This is no longer done. To remove the javascript you must delete everything inside and including the script tag's al well as the noscript tag's so the browser will generate the movie content. This can be done on a site wide basis easily using dreamweavers find and replace utility. Once the scripting has been removed the object will be generated on it's own with all of the new or modified options applied.

Option 2 is much easier. If you shutdown dreamweaver first then take the files from:
%windir%:\Program Files\Macromedia\Dreamweaver 8\Configuration\ActiveContent\Converters
if you were working with DW8, or
%windir%:\Program Files\Adobe\Adobe Dreamweaver CS3\configuration\ActiveContent\Converters
if you were working with CS3 and put them in
%windir%:\Program Files\Adobe\Adobe Dreamweaver CS4\configuration\ActiveContent\Converters
When you start up dreamweaver and modify a flash movie the RunActiveContent script will be updated just like CS3 or DW8.02. There should be 6 files in the old DW folder:
  1. ActiveContent.js
  2. ActiveContent.xml
  3. ActiveX.htm
  4. ActiveX.js
  5. Adobe.htm
  6. Adobe.js
all 6 need to be moved and if the new folder has the file ActiveContent.xml already in it just override the new one.

This is only needed if you are making changes to pages originally made from older DW's with the browser safe script option enabled, it is not necessary for new aspx pages made because the RunActiveContent script is not generated. I have included a copy of the missing files.

Converters.rar The missing files

http://www.inetsupervisor.com/Support/default.htm “InetSupervisor SUPPORT”

http://www.inetsupervisor.com/Products/Default.htm “Quark Communications PRODUCTS”

http://www.inetsupervisor.com “InetSupervisor HOME”

Labels: , , ,

Wednesday, September 3, 2008

Passing URLconfiguration parameters to the Trend Viewer

If you are using the latest version of our TrendViewer (as of this writing in the beta download folder with August 15th date or later), the ability to pass URL parameters to configure the trend viewer is available. This can be useful for users that view or want to view the same information on a regular bases. A link can be made to set up the viewer on load so the user does not have to choose the same points and set the date range each time they want to see a specific report. The long time Inetsupervisor users should know about setting up URL parameters to web pages, but I will go over it again for newer user.


URL parameters are a string of ampersand(&) delimited variables, and there associated values, that can be added to the end of a web page address(link). These vars, if the web page knows what to do with them, can configure or modify the web page when it loads. Also as in our case the web page can pass it to an object in the web page such as a flash movie. The start of the string of vars is always a question mark symbol(?) this will tell the web page that variables are coming. The next is to put the parameter name (remember case sensitive) followed by an equal sign(=) then the value of the parameter. If there are more then 1 parameters then an ampersand(&) needs to follow the value and before the next parameter's name, then complete as the first. Do the same for any additional parameter's.


The Trend Viewer will accept 13 configuration parameters:

  1. ids This is a comma delimited string of Inetsupervisor point id's. When this parameter is passed the viewer will automatically choose the points in the string on load.

  2. rids This is the same as ids but it will assign the point id's to the right side Y axis. This can be used to overlay trend graphs with different value ranges.

  3. startoffset This is an number used to specify an amount of days to start the viewer prior to the current date. For instance if you wish to start the selected view for the last 7 days you would enter 7.

  4. pen1 – pen10 These are comma delimited strings used to define the color, type, and form of the individual pen lines of data. The string must contain the color, in RGB format, then the pen type (available pen types: line(default) , plot, area or column) typed out (case sensitive), then the pen form (available pen forms: curve(default), segment, step, reverseStep, vertical or horizontal) typed out (case sensitive).

Some examples:

    When the viewer opens I want to load point 23.

  1. Open the tree editor

  2. Drag over the QTrendsById.aspx web page from the sysapp folder.

  3. Double click to open the properties.

  4. At the bottom property URL add ?ids=23 to the end of the string

  5. Save and refresh tree

    When you click the link the viewer will open to point 23 loaded with todays data

        Add points 24 and 67

  6. Open the tree editor

  7. Double click to open the properties of the above node.

  8. Change ?ids=23 to ?ids=23,24,67

  9. Save and refresh

    Now it loads points 23, 24 and 67


Move point 67 to the right Y axis and load 5 days of data. Same as above, but change ?ids=23,24,67 to ?ids=23,24&rids=67&startoffset=5 Now point 67is attached to the right Y axis and 5 days of data shows

Show point 67 as a blue column type grid, change to ?ids=23,24&rids=67&startoffset=5&pen3=0x0000FF,column,curve Notice that the last parameter is pen3 not pen1 that is because when the points are loaded the viewer loads all the points from ids first then the points from rids, so 67 would be the 3rd series in the line. Not all the parameter's have to be used and they do not need to be in any order, but remember if you are specifying a pen then it has to be color,type,form and all parts of the string need to be there, even if you are using a chart type that requires no information from the form like a plot. These reports can also be linked not only from the tree but also buttons, text, browser favorites, custom flash or any place a web link can be placed.


You can also view a tutorial on using the Trend Viewer on the web at http://www.inetsupervisor.com/Support/Multimedia/default.htm




Labels: ,

Thursday, August 28, 2008

Enumerated variables

Enumerated variables or types are data multiple data “chunks” grouped together into one piece of information. The 2 main reasons for enumerated data are

  1. Controllers that are limited in the amount of variables they are allowed to expose to the network.

  2. Network commands that require more then a simple ON|OFF or analog value.

The data is delimited in some way to recognize the individual parts, like a comma or carrot. This delimiter is what we will use to parse out some data, work with the individual parts, then reassemble the data and send it back to the controller.


In this example we will be working with a LonWorks UNVT made by the Distech company. The process would hold true for any enumerated data from any protocol once it has been imported into the Atlas database. This variable is used to modify or override the internal vars and physical input and output values in the controller. The variable has 4 parts separated by white space(aka empty char). The first is the type field, this is a string that specifies what type of var to override. Second is the index of the type field, this is a unsigned short. Third is the mode, another string specifying manual or automatic operation. The last is the value to be applied to the overriding var it is a signed long.



//////////////////////////////////Code//////////////////////////////////////////////////////////////////////////////////////////////////



_global.style.setStyle("themeColor", "haloBlue");//change the style

/*********************Initilize the local vars************************************/

con.ID = PointID;// Assign the point ID to work with

var output_timer:Number = setInterval(evaluateOutput, 3000);// Set timer to display updated values

var type:String = "";

var index:Number = 0;

var md:String = "";

var val:Number = 0;

var overrideVal:String = "";

var sentOverride:Boolean = false;

/******************Start the UI not edible until a good value comes in***********/

IntValType.enabled = false;

Index.enabled = false;

Mode.enabled = false;

Value.enabled = false;

Send.enabled = false;




The first bit of code just sets up the “theme” for the movie, internal variables to handle the parsed data, and disables the UI for now. By the way I am using 2 number steppers for the index and value, 2 combo-boxes for the type and mode and a button for sending the override value for my UI.




//********************* Main body functions ***************

function evaluateOutput(){

if (!sentOverride){//make sure we are not sending an override or making one

if ((String(con.output).indexOf("?") == -1) && (con.output != undefined)){//check for a good connection to the controller and a valid value

type = String(con.output).split(" ")[0];//load the public var

IntValType.text = type;//update the ui

index = Number(String(con.output).split(" ")[1]);

Index.value = index;

md = String(con.output).split(" ")[2];

Mode.text = md;

val = Number(String(con.output).split(" ")[3]);

Value.value = val;//update the ui

}

else if (String(con.output).indexOf("?") > -1){//updat ethat the controller is not communicating

IntValType.text = "Error";

Index.value = 0;

Mode.text = "Error";

Value.value = 0;

}

if (con.isNew == "1"){//if the val is new then allow the ui to work

IntValType.enabled = true;

Index.enabled = true;

Mode.enabled = true;

Value.enabled = true;

Send.enabled = true;

}

}

else if(con.output == overrideVal){

sentOverride = false;

type = String(con.output).split(" ")[0];//load the public var

IntValType.text = type;//update the ui

index = Number(String(con.output).split(" ")[1]);

Index.value = index;

md = String(con.output).split(" ")[2];

Mode.text = md;

val = Number(String(con.output).split(" ")[3]);

Value.value = val;//update the ui

IntValType.enabled = true;

}

}

stop();//stops the continuation of frames



In my main function I first check to see if I should pause the updating of the UI because we are in the process of making or sending an override and that the connector has a value and the value is not ??? because the drive cannot connect with the controller. If that is good then we get to the meat of this lesson. Since we know the delimiter and how many parts to expect we can now parse the data and put it into our individual vars created above. First we take the output and cast it into a string type String(con.output) then split that string with our delimiter String(con.output).split(“ “). The data will now be in an array of parts and we can then choose the piece to grab and assign to the internal var type = String(con.output).split(“ “)[0]. Do this 3 more times assigning the appropriate piece to all of the internal vars and now you can adjust them , display them or do what ever you want with them as individuals.




//////////////////////////////////Code//////////////////////////////////////////////////////////////////////////////////////////////////



on (click){//when button is mouse clicked:

_parent.overrideVal = _parent.type+" "+String(_parent.index)+" "+_parent.md+" "+String(_parent.val);

_parent.con.sendOverride(_parent.PointID,_parent.overrideVal);//send and override with the current point ID and the override value

}



When you are done adjusting the individual vars you will need to send them back to the controller for processing. To do this you need to assemble the individuals back into the form that the controller will accept. This is done by assembling a string with the values and appropriate delimiter, and sending thru the connector. _parent.overrideVal = _parent.type+" "+String(_parent.index)+" "+_parent.md+" "+String(_parent.val); assembles the string with a “ ”(white space) between each. _parent.con.sendOverride(_parent.PointID,_parent.overrideVal); sends the override.


This could also be done without assigning the array to the individual vars and then reassembling with a for loop, but if you go that route remember that each index of the array will be a string type and other types will need to be cast before they work as expected, also keep a list of what index holds what information because tempArray[7] is not as descriptive as mode, or value, or alarm.

You can download the source and compiled here

Fx-UNVT-modify_internal_val.zip

Labels: , , ,