AS3 array to clean up long code? - actionscript-3

I would like a better way to write this possibly using an array but I have been unsuccessful. See my code below. I need to add more details to post this but i can't think of more to say. I suppose I eventually need to have to set up a row of btnA show both B and C simultaneously as well. That would also be helpful.
I have a chart that either turns on a square or turns it off when clicked, for example btn3 toggles the visibility of checkMark3, works as written, but when I have 50 or 60 options of clicking the code is exhausting to write and becomes unruly
btnB1.addEventListener (MouseEvent.CLICK, showB1);
function showB1(event:MouseEvent) {
if (checkMarkB1.alpha == 1){
checkMarkB1.alpha = 0;} else {checkMarkB1.alpha = 1}
}
btnB2.addEventListener (MouseEvent.CLICK, showB2);
function showB2(event:MouseEvent) {
if (checkMarkB2.alpha == 1){
checkMarkB2.alpha = 0;} else {checkMarkB2.alpha = 1}
}
btnB3.addEventListener (MouseEvent.CLICK, showB3);
function showB3(event:MouseEvent) {
if (checkMarkB3.alpha == 1){
checkMarkB3.alpha = 0;} else {checkMarkB3.alpha = 1}
}
btnB4.addEventListener (MouseEvent.CLICK, showB4);
function showB4(event:MouseEvent) {
if (checkMarkB4.alpha == 1){
checkMarkB4.alpha = 0;} else {checkMarkB4.alpha = 1}
}
btnC1.addEventListener (MouseEvent.CLICK, showC1);
function showC1(event:MouseEvent) {
if (checkMarkC1.alpha == 1){
checkMarkC1.alpha = 0;} else {checkMarkC1.alpha = 1}
}
btnC2.addEventListener (MouseEvent.CLICK, showC2);
function showC2(event:MouseEvent) {
if (checkMarkC2.alpha == 1){
checkMarkC2.alpha = 0;} else {checkMarkC2.alpha = 1}
}
btnC3.addEventListener (MouseEvent.CLICK, showC3);
function showC3(event:MouseEvent) {
if (checkMarkC3.alpha == 1){
checkMarkC3.alpha = 0;} else {checkMarkC3.alpha = 1}
}
btnC4.addEventListener (MouseEvent.CLICK, showC4);
function showC4(event:MouseEvent) {
if (checkMarkC4.alpha == 1){
checkMarkC4.alpha = 0;} else {checkMarkC4.alpha = 1}
}

Add all your buttons to an array, and all your checkMarks to another array. Make sure that the order of the items in the array means that the position of each button in the buttons array corresponds with the position of its associated checkMark in the checkMarks array.
//add an event listener to all buttons
for(var i:uint=0; i<buttons.length; i++){
buttons[i].addEventListener(MouseEvent.CLICK, showBox);
}
//showBox function
function showBox(evt:MouseEvent):void{
for(var a:uint = 0; a<buttons.length; a++){
if (evt.target == buttons[a]){
if(checkMark[a].alpha == 1){
checkMark[a].alpha = 0;
} else {
checkMark[a].alpha = 1;
}
}
}
}
This should mean you can just add as many buttons and checkMarks as you like to the array, as long as you add them in the right order and always have a checkMark for every button.

Trex had it I just needed to get it right, this dynamically makes the names and sets the visibility of the check marks. So for a grid that has many check marks to use and turn on and off this is what I ended up with,
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.DisplayObject;
// The two parameters below will be used to dynamically generate the clipinstance names
var letters: Array = ['A', 'B', 'C', 'D', 'E'];
var index: int = 9;
for (var i: int = 1; i <= index; i++) {
// we keep a reference of the movie clip because the scope is lost in the anonymous event listener
var mc = this;
// instead of setting checkMarkE9.visible = false; we do all of this dynamically
trace('Updating visibility of : ' + 'checkMark' + letters[1] + i);
this['checkMark' + letters[1] + i].visible = false;
trace('Updating visibility of : ' + 'checkMark' + letters[2] + i);
this['checkMark' + letters[2] + i].visible = false;
trace('Updating visibility of : ' + 'checkMark' + letters[3] + i);
this['checkMark' + letters[3] + i].visible = false;
trace('Updating visibility of : ' + 'checkMark' + letters[4] + i);
this['checkMark' + letters[4] + i].visible = false;
// dynamically adding event listeners
this['btn' + letters[0] + i].addEventListener(MouseEvent.CLICK, function (e: MouseEvent) {
var btnIndex: String = getLastLetter(e.currentTarget.name);
trace('Updating visibility of : ' + 'checkMark' + letters[1] + btnIndex);
trace('Updating visibility of : ' + 'checkMark' + letters[2] + btnIndex);
trace('Updating visibility of : ' + 'checkMark' + letters[3] + btnIndex);
trace('Updating visibility of : ' + 'checkMark' + letters[4] + btnIndex);
mc['checkMark' + letters[1] + btnIndex].visible = true;
mc['checkMark' + letters[2] + btnIndex].visible = true;
mc['checkMark' + letters[3] + btnIndex].visible = true;
mc['checkMark' + letters[4] + btnIndex].visible = true;
});
// dynamically add event listeners for cells
this['btn' + letters[1] + i].addEventListener(MouseEvent.CLICK, function (e: MouseEvent) {
switchVisibility(mc['checkMark' + letters[1] + getLastLetter(e.currentTarget.name)]);
});
this['btn' + letters[2] + i].addEventListener(MouseEvent.CLICK, function (e: MouseEvent) {
switchVisibility(mc['checkMark' + letters[2] + getLastLetter(e.currentTarget.name)]);
});
this['btn' + letters[3] + i].addEventListener(MouseEvent.CLICK, function (e: MouseEvent) {
switchVisibility(mc['checkMark' + letters[3] + getLastLetter(e.currentTarget.name)]);
});
this['btn' + letters[4] + i].addEventListener(MouseEvent.CLICK, function (e: MouseEvent) {
switchVisibility(mc['checkMark' + letters[4] + getLastLetter(e.currentTarget.name)]);
});
}
// switches a display item visiblity
function switchVisibility(display: DisplayObject): void {
display.visible = !display.visible;
}
// get the last letter of a string
function getLastLetter(str: String): String {
return str.substr(str.length - 1, str.length);
}

Related

Convert JSON data to table

I am trying to create table from my JSON data which looks like this:
It works for a specific JSON data:
var items = [
{"Name":"A","Type":2,"Result":"0"},
{"Name":"A","Type":1,"Result":"1"},
{"Name":"B","Type":2,"Result":"1"},
{"Name":"B","Type":1,"Result":"0"},
]
But, it doesn't create table correctly if the columns ("Type") is random
var items = [
{"Name":"A","Type":5,"Result":"1"}
{"Name":"A","Type":2,"Result":"0"},
{"Name":"A","Type":1,"Result":"1"},
{"Name":"B","Type":3,"Result":"1"},
{"Name":"B","Type":2,"Result":"1"},
{"Name":"B","Type":1,"Result":"0"},
]
Can someone tell me what's the issue with my code?
I want to create table for dynamic JSON data which may not have cell values for all the columns. With this code, I don't see entry in column 5 for A as 1.
function get_prop(obj, prop) {
return prop.split('.').reduce((o,k) => obj[k], obj);
}
function coll2tbl(json, row_header, col_header, cell) {
var table = {};
var row_headers = [];
var cols = {};
json.map(function(a) {
var h = get_prop(a, row_header);
if (h in table === false) {
table[h] = {};
row_headers.push(h);
}
var c = get_prop(a, col_header);
cols[c] = null;
table[h][c] = get_prop(a, cell);
});
var cells = [];
for (var row in table) {
cells.push(Object.values(table[row]));
}
console.log('row_headers' + row_headers);
console.log('Object.keys(cols)' + Object.keys(cols));
console.log('cells' + cells);
var headerRow = '<th>' + capitalizeFirstLetter('TestName') + '</th>';
var colKeys = Object.keys(cols);
colKeys.map(function(col) {
headerRow += '<th>' + capitalizeFirstLetter(col) + '</th>';
});
var bodyRows = '';
for (var i in cells) {
bodyRows += '<tr>';
bodyRows += '<td>' + row_headers[i] + '</td>';
for (var j in cells[i]) {
console.log('Processing row: ' + row_headers[i] + ' result: ' + cells[i][j] + ' i=' + i + ' j=' + j);
bodyRows += '<td>';
if (cells[i][j] === "1") {
bodyRows += '<font color="green">' + cells[i][j] + '</font>';
}
else if (cells[i][j] === "0") {
bodyRows += '<font color="red">' + cells[i][j] + '</font>';
}
else if (cells[i][j] === "-1") {
bodyRows += '<font color="orange">' + cells[i][j] + '</font>';
}
else {
bodyRows += "-";
}
bodyRows += '</td>';
}
bodyRows += '</tr>';
}
//return { row_headers, col_headers: Object.keys(cols), cells };
return ('<table> <thead><tr>' + headerRow + '</tr></thead><tbody>' + bodyRows + '</tbody></table>');
}
function capitalizeFirstLetter(string) {return
string.charAt(0).toUpperCase() + string.slice(1);
}
coll2tbl(items, 'Name', 'Type', 'Result');
My table should like like this:
Name 1 2 3 4 5
A 1 1 - - 1
B 1 1 1 - -
The answer https://stackoverflow.com/a/52199138/10320683 is of course correct, but if you need or want to stick to your specific code, you can put this below your json.map (which should by the way use forEach and not map, since you do not use the returned array anyways)
for (var col in cols) {
for (row in table) {
if (!table[row].hasOwnProperty(col)) {
table[row][col] = "-";
}
}
}
The reason why your code did not work is that by iterating over the rows, you do not get all the possible type properties, which becomes clear if you inspect your table variable: { a: {1: "1", 2: "0", 5: "1"}, b: {...}} (this is missing the 3 type property), so by calling Object.values(table[row]) later on, you get the following array for your cells: ["1", "0", "1"], but you do have 4 columns, so the "Type 5" result (1) gets shifted one column to the left.
Also, you need to be careful because your code is relying on the sorting that Object.values() produces, which means that if you want to change the order of your columns, your code would not work.

nodejs json.stringify a 1gb object running out of memory

I'm trying to json.stringify a 1 gb object so that I can write it to disk. I get FATAL ERROR: JS Allocation failed - process out of memory
What can I do to stringify successfully?
You can stringify bit by bit manually: if y is a key of x, then JSON.stringify(y) + ":" + JSON.stringify(x[y]) gives you one segment.
Using fs.appendFileSync, for example, you can use:
var output = "out.json";
fs.writeFileSync(output, "{");
var first = true;
for(var y in x) {
if(x.hasOwnProperty(y)) {
if(first) first = false;
else fs.appendFileSync(output, ",");
fs.appendFileSync(output, JSON.stringify(y) + ":" + JSON.stringify(x[y]))
}
}
fs.appendFileSync(output, "}");
You can also use a Write Stream
Extended with Object, Array checker
var first, y, i$, ref$, len$, toString$ = {}.toString;
switch (toString$.call(x).slice(8, -1)) {
case 'Object':
fs.writeFileSync(output, '{');
first = true;
for (y in x) {
if (x.hasOwnProperty(y)) {
if (first) {
first = false;
} else {
fs.appendFileSync(output, ',');
}
fs.appendFileSync(output, JSON.stringify(y) + ':' + JSON.stringify(x[y]));
}
}
fs.appendFileSync(output, '}');
break;
case 'Array':
fs.writeFileSync(output, '[');
first = true;
for (i$ = 0, len$ = (ref$ = x).length; i$ < len$; ++i$) {
y = ref$[i$];
if (first) {
first = false;
} else {
fs.appendFileSync(output, ',');
}
fs.appendFileSync(output, JSON.stringify(y));
}
fs.appendFileSync(output, ']');
break;
default:
fs.writeFileSync(output, JSON.stringify(x));
}

Creating A Customizable Count-Up Function in CSS, HTML or in Javascript?

I have a countdown function (the code for which, is below) that is small and alligned to the top left corner.
I would like to be able to customize the size, allignment, back color, fore color, and also have a button to stop, start, and clear the timer.
Secondly, I want the counter to show "00:00:00" at the start, and when it reaches "00:00:59", I want it to roll over to "00:01:00" showing that 1 minute has passed.
I would think that CSS/HTML would be the most appropriate language to do this in to acheive the desired visual effect but Javascript seems to have more arithmatic/parsing functionality.
<br><script language="JavaScript">
function calcage(secs, num1, num2) {
s = ((Math.floor(secs/num1))%num2).toString();
if (LeadingZero && s.length < 2) {
s = "0" + s;
return "<b>" + s + "</b>";
}
}
function CountBack(secs) {
if (secs < 0) {
document.getElementById("cntdwn").innerHTML = FinishMessage;
return;
}
DisplayStr = DisplayFormat.replace(/%%D%%/g,calcage(secs,86400,100000));
DisplayStr = DisplayStr.replace(/%%H%%/g, calcage(secs,3600,24));
DisplayStr = DisplayStr.replace(/%%M%%/g, calcage(secs,60,60));
DisplayStr = DisplayStr.replace(/%%S%%/g, calcage(secs,1,60));
document.getElementById("cntdwn").innerHTML = DisplayStr;
if (CountActive) {
setTimeout("CountBack(" + (secs+CountStepper) + ")", SetTimeOutPeriod);
}
}
function putspan(backcolor, forecolor) {
document.write("<span id='cntdwn' style='background-color:" + backcolor + "; color:" + forecolor + "'></span>");
}
if (typeof(BackColor)=="undefined") {
BackColor = "black";
}
if (typeof(ForeColor)=="undefined") {
ForeColor= "white";
}
if (typeof(TargetDate)=="undefined") {
TargetDate = "12/31/2050 5:00 AM";
}
if (typeof(DisplayFormat)=="undefined") {
DisplayFormat = "%%H%%:%%M%%:%%S%%";
}
if (typeof(CountActive)=="undefined") {
CountActive = true;
}
if (typeof(FinishMessage)=="undefined") {
FinishMessage = "";
}
if (typeof(CountStepper)!="number") {
CountStepper = -1;
}
if (typeof(LeadingZero)=="undefined") {
LeadingZero = true;
}
CountStepper = Math.ceil(CountStepper);
if (CountStepper == 0) {
CountActive = false;
}
var SetTimeOutPeriod = (Math.abs(CountStepper)-1)*1000 + 990;
putspan(BackColor, ForeColor);
var dthen = new Date(TargetDate);
var dnow = new Date();
if(CountStepper>0) {
ddiff = new Date(dnow-dthen);
}
else {
ddiff = new Date(dthen-dnow);
}
gsecs = Math.floor(ddiff.valueOf()/1000);
CountBack(gsecs);
</script>
I would use a simpler solution, using javascript Date object, sum miliseconds on a time counter then format the miliseconds as time.
some references :
Date object and functions : http://w3schools.com/jsref/jsref_obj_date.asp

jQuery click() each() unique?

I want to have multiple span.play without IDs which can be clicked and play some audio file.
Problem: Display the duration on only the current file $(this)
$('.play').each(function() {
$(this).append('<span class="playIcon"><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/7/76/Fairytale_player_play.png/14px-Fairytale_player_play.png"></span><span class="playDur"></span>');
$(this).click(function() {
var file = this.firstChild;
if (file.paused != false) {
//+ stop all others before playing new one
file.play();
} else {
file.pause();
}
file.addEventListener("timeupdate", function() {
var len = file.duration,
ct = file.currentTime,
s = parseInt(ct % 60),
m = parseInt((ct / 60) % 60);
if (s < 10) {
s = '0' + s;
}
$(".playDur").html(' (' + m + ':' + s + ')');
if (ct == len) {
$(".playDur").html('');
}
}, false);
});
});
Test:
http://jsfiddle.net/sQPPP/
http://jsfiddle.net/sQPPP/1/ - using $(this).children( ".foo" )
You need to save .play jQuery object in a variable, as this changes within the addEventListener callback.
http://jsfiddle.net/sQPPP/2/
$('.play').each(function(index) {
var $play = $(this);
$play.append('<span class="playIcon"><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/7/76/Fairytale_player_play.png/14px-Fairytale_player_play.png"></span><span class="playDur"></span>');
$play.click(function() {
var file = this.firstChild;
if (file.paused != false) {
//+ stop all others before playing new one
file.play();
} else {
file.pause();
}
file.addEventListener("timeupdate", function() {
var len = file.duration,
ct = file.currentTime,
s = parseInt(ct % 60),
m = parseInt((ct / 60) % 60);
if (s < 10) {
s = '0' + s;
}
$play.children( ".playDur" ).html(' (' + m + ':' + s + ')');
if (ct == len) {
$play.children( ".playDur" ).html('');
}
}, false);
});
});​

Need help with setTextFormat (AS3)

I'm trying to make an rss reader with Flash CS5.5. It's almost finished but i couldn't style news titles. The problem is some parts of a textfield needs to be bold and colored. Here's my code:
var num:int = 0;
var tempText:String;
var titleStr:String;
var timeStr:String;
var descriptionStr: String;
function rssLoaded(evt:Event):void {
rssXML = XML(rssLoader.data);
// trace(rssXML);
num = 0;
for (var rssTitle:String in rssXML.channel.item) {
// Set title
tempText = rssXML.channel.item[rssTitle].title;
tempText = tempText.slice(6);
titleStr = tempText + "\r\n";
// Set description
tempText = rssXML.channel.item[num].description;
// Detect if beginning with tags
if ((tempText.charCodeAt(0) == 60) && (tempText.charCodeAt(1) == 73)) {
tempText = tempText.slice(tempText.search("/>") + 2, tempText.search("<img"));
} else {
tempText = tempText.slice(0, 140);
}
// Detect if still contains tags
if ((tempText.indexOf("<") != -1) || (tempText.indexOf(">") != -1)) {
num++;
continue;
}
// Detect if beginning with space
for (var num2:int=0; tempText.charCodeAt(0) == 32 || tempText.charCodeAt(0) == 160; num2++) {
tempText = tempText.slice(1);
}
descriptionStr = tempText + "...\r\n\r\n";
main_txt.appendText(titleStr);
main_txt.setTextFormat(title_tf, main_txt.text.length - titleStr.length, titleStr.length-2);
main_txt.appendText(descriptionStr);
num++;
}
}
var title_tf:TextFormat=new TextFormat();
title_tf.bold=true;
When I test the code, I'm seeing that only the first line is bold, while all titles needs to be bold. Sorry for my English.
Sincerely
It would be much simpler to style the text using the TextField.htmlText property:
title_tf.htmlText = "<b>" + titleTextString + "</b><br/>" + bodyTextString;
This approach would also allow you to use CSS like this:
title_tf.styleSheet = myImportedStyleSheet;
title_tf.htmlText = "<span class='titleClass'>" + titleTextString + "</span><br/><span class='bodyClass'>" + bodyTextString + "</span>";