Thursday, March 31, 2011

Using a timed NSInvocation to animate the population of a UITableView

While there's probably dozens of ways to animate the population of a UITableView, here's one way using NSInvocation with a timer. I hadn't used NSInvocation before so this was a good exercise.

The example:
1. Configures the cell
2. Sets the cell's "hidden" attribute to true
3. Creates an NSInvocation for the "setHidden" attribute of the cell
4. Configures the NSInvocation argument to set setHidden to "NO"
5. Creates a timer that fires the NSInvocation at a relative time


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
        static NSString *CellIdentifier = @"Cell";
    
        UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
                cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
                
        }
        (*** set the cell data here)

        [cell setHidden:YES];
        
        NSMethodSignature * mySignature = [UITableViewCell instanceMethodSignatureForSelector:@selector(setHidden:)];
        NSInvocation * myInvocation = [NSInvocation invocationWithMethodSignature:mySignature];
        NSNumber *n = [NSNumber numberWithBool:NO];
        [myInvocation setArgument:&n atIndex:2];
        [myInvocation setTarget:cell];
        [myInvocation setSelector:@selector(setHidden:)];
        
        [NSTimer scheduledTimerWithTimeInterval:.1 * indexPath.row invocation:myInvocation repeats:NO];
        
        return cell;
}

Thursday, March 10, 2011

Using Em and Ex

For the last couple of years I've been using CSS stylesheets pretty heavily in my app designs. Typically, I'd define elements in the CSS in pixel (px) units.

However, one thing that's become an issue when designing for different size screens (e.g. ipod/ipad) is the font size. Not only should you make sure the font is appropriate, but you should also take a look at other layout content including margins and images.

There's a couple of ways of addressing this problem, but perhaps the easiest is to take advantage of the "em" and "ex" ways of defining relative sizes in CSS.

According to about 30 seconds of Google research, Em, back in the hardcopy print days, was the width of the "M" character for a given font. Ex was the height of the "X" character. So, if one wants to define a margin that scales horizontally relative to the given font, then define the margin in terms of "Em".

So using em units works great for margins. It also works great for relative fonts. And it even works for specifying image sizes.

I could write my own example, but here's a good one that's already out there

Wednesday, March 2, 2011

Converting code for Blogger

Here's a simple PERL script that converts a code file for pasting into Blogger. And yes, I used it to convert itself for this post. HOW COOL IS THAT??? LOL. If anyone knows of a free, online one that's better, lemme know.

pastable.pl



if (@ARGV < 1){
        die "Usage filename\n";
}
$filename = shift(@ARGV);

@fn = split(/\./,$filename);
$outname = $fn[0]."-pastable\.html";

open (INPUT,"<$filename");
open (OUTPUT,">$outname");

print OUTPUT "<font size=-1>";
while (<INPUT>){
        $line = $_;

        $line =~ s/\&/&amp;/g;        
        $line =~ s/</&lt;/g;        
        $line =~ s/>/&gt;/g;
        $line =~ s/\"/&quot;/g;
        $line =~ s/\n/<BR>/g;
        $line =~ s/\t/        /g;
        $line =~ s/ /&nbsp;/g;

        print OUTPUT $line;
}
print OUTPUT "</font>";

HTML5 Animated Graph / First Post

This blog is intended to be a repository of things I want to remember.

I typically use a journal for that purpose, but considering all I've gained from others sharing their experiences and code on the internets, I feel like I should share some back.

First up, here's a simple animated graph done using HTML5. I used to do a lot of graph writing in a former life but HTML5 beats the hell out of doing it in Java. I'm not sure which browsers besides Safari will render it (I know my version of Firefox didn't). Feel free to use it for whatever - there's better examples out there but this should be a decent starting place for anybody trying to use HTML5 to generate a graph. Just cut-n-paste the code below into an HTML file and it should run in Safari or other HTML5-enabled browsers.

Here's what the rendered graph should look like:



And here's the code:

<!--- Simple HTML5 Line Percentage Chart --->

<canvas width=320 height="170"></canvas>

<script>

var context = document.getElementsByTagName('canvas')[0].getContext('2d');

// fill the background (if desired)
//context.fillStyle = 'rgba(0,0,200,0.1)';
//context.fillRect(0, 0, context.canvas.width, context.canvas.height);

// sample data
var data = new Array();
for (i=0; i <= 11; i++){
        data[i] = 100 * Math.random();
}

// create some room for the margins
var xmargin=context.canvas.width * .12;
var ymargin=context.canvas.height * .15;

// create my own rect structure
function rect(x, y, w, h)
{
   this.x = x;
   this.y = y;
   this.w = w;
   this.h = h;
}

// create the "innerRect" where most of the drawing occurs
var ir = new rect(xmargin, ymargin, context.canvas.width-(1.5*xmargin), context.canvas.height - (2*ymargin));

// translate the drawing to be from the top left corner of the inner rect
context.translate(ir.x, ir.y);

// scale the Y to the Y axis (0 - 100)
context.scale(1, ir.h/100.0);

function doTitles() {
        var leftTitle = "Left Title";
        var topTitle = "The Top Title";

        context.fillStyle = 'rgba(0,0,0,.5)';
        context.strokeStyle = 'rgba(0,0,0,.5)';

        // left
        context.save();
        context.rotate((Math.PI/180.0) * -90.0);
        context.textAlign = "center";
        context.textBaseline = "middle";
        context.font = "10px arial";
        context.fillText(leftTitle, -50, -30);
        context.strokeText(leftTitle, -50, -30);
        context.restore();

        // top
        context.font = "12px arial";
        context.textAlign = "center";
        context.textBaseline = "bottom";
        context.fillText(topTitle,ir.w/2.0,0);
        context.strokeText(topTitle,ir.w/2.0,0);
}
doTitles();


// set up an inner margin so we don't crowd the left and right sides
var innermargin = 5;

// compute the x-offset between adjacent plotted points.
var offset = (ir.w-(2*innermargin)) / (data.length-1);

// initialize our data pointers
var ptr = 0;
var lastX = innermargin;
var lastY = 100-data[ptr];
ptr = 1;



function drawGrid() {
   context.save();

   var y = 100;

   // draw the outer border
   context.lineWidth = 1;
   context.strokeRect(0,0,ir.w,100);

   context.font = "10px arial";

   for (i=0; i <= 10;i++){
          context.beginPath();

        // draw Y axis tics.  For even-numbered tics, draw them longer and add a label
           context.strokeStyle = 'rgba(0,0,0,.3)';
        var x = -2;
        var x1 = 0;
        if ((i % 2) == 0){
           x = -5;
           x1 = 3;
        }
        context.moveTo(x, y);
        context.lineTo(x1, y);
           context.stroke();

        if ((i % 2) == 0){
                context.fillStyle = 'rgba(0,0,0,.5)';
                context.strokeStyle = 'rgba(0,0,0,.5)';
                context.textAlign = "right";
                context.textBaseline = "middle";
                context.fillText((i*10),0-7,y);
                context.strokeText((i*10),0-7,y);
        }

        // draw an alternating "band" effect.
        if ((i % 2) == 0 && i != 10){
             context.fillStyle = 'rgba(100,100,100,0.1)';
              context.fillRect(0, y-10, ir.w, 10);
        }
        y -= 10;
   }
        
   // now draw the x-axis tics and labels. 
   var x = innermargin;
   var y = 100;

   // if we have more than 20 tics, we're only going to show every 5th one (and also the first one)
   var domod5 = 0;
   if (data.length > 20)
        domod5 = 1;

   for (i=0; i < data.length;i++){
          context.beginPath();
        context.moveTo(x, y-2);
        context.lineTo(x, y+2);
           context.stroke();

        if (domod5 == 0 || domod5 && ((i+1)%5) == 0 || i == 0){
                context.fillStyle = 'rgba(0,0,0,.5)';
                context.strokeStyle = 'rgba(0,0,0,.5)';
                context.textAlign = "center";
                context.textBaseline = "top";
                var tx = (i+1)+"";

                context.fillText(tx,x,y+2);
                context.strokeText(tx,x,y+2);
        }
        x += offset;

    }
   context.restore();
}
drawGrid();



// draw a line segment - we'll use the setInterval to animate
function drawLine() {
   if (ptr == data.length){
        clearInterval(drawLine);
        return;
   }
   context.save();

   context.beginPath();
   context.lineWidth = 2;
   context.lineJoin = "miter";
   context.lineCap = "round";
   context.moveTo(lastX, lastY);
   lastX = lastX + offset;
   lastY = 100 - data[ptr];
   context.lineTo(lastX,lastY);
  // context.bezierCurveTo(lastX-(offset/2.0),lastY+25,lastX-(offset/2.0),lastY-25,lastX,lastY);

   context.strokeStyle = 'rgba(0,250,0,1)';
   context.shadowOffsetY = 0;
   context.shadowBlur = 12;
   context.stroke();
   context.restore();

   ptr++;
}
setInterval(drawLine, 50);

 

</script>