Ming the Tutorial


My Big Example

Since the dawn of time, man has pondered the imponderable, a question which defines his place in the universe, the burning question of the ages: will there ever be a flash implementation of a slashdot headline scroller? Lo, the time is nigh, our prayers are answered.

First, let's take a look. Pretty cool, eh? Actually, don't answer that..

Here's how it works. First, we keep a local copy of the slashdot.xml headline file to avoid overloading slashdot.org; only if the file is 30 minutes old or more are we allowed to grab another copy.

// if file is older than 30 minutes, go fetch a new copy

$s = stat("slashdot.xml");

if(!$s || $s[9] < time()-1800)  // idx 9 is last modification time
{
  $page = file("http://slashdot.org/slashdot.xml");
  $page = implode("", $page);

  fwrite(fopen("slashdot.xml","w"), $page);
}
else
{
  $page = file("slashdot.xml");
  $page = implode("", $page);
}
Now we use this handy regex to rip out the urls and headlines:
# borrowed from http://www.wiredstart.com

preg_match_all("/<title\>(.+?)<\/title\>\s+<url\>(.+?)<\/url\>/i",
               $page, $news, PREG_PATTERN_ORDER);
$i = 0;

while(list(,$match) = each($news[1]))
{
  $url[$i] = $news[2][$i];
  $match = str_replace('&amp;','&',$match);
  $match = str_replace('&lt;','<',$match);
  $match = str_replace('&gt;','>',$match);
  $match = str_replace('<i>','',$match);
  $match = str_replace('</i>','',$match);

  $title[$i] = $match;
  ++$i;
}

$count = $i;
Since there doesn't seem to be an inverse of php's htmlentities function, we replace the more common entities with normal text. Now let's make the SWFMovie and grab a font:
$m = new SWFMovie();
$m->setDimension(1200,60);
$m->setBackground(0, 0x66, 0x66); // minty slashdot green!
$m->setRate(24.0);

$f = new SWFFont('Techno.fdb');
SWFButton

Since we're both getting tired by now, I'll just tell you enough about buttons to make the following make sense. Buttons can have a number of shapes associated with them- an up shape, the button's general appearace; an over shape, displayed when the mouse moves over the button; a down shape, displayed when the user clicks down on the button; and a hit region, which is never shown but defines the clickable area of the button.

You create a button with

$b = new SWFButton();
and add a shape to the button states with
$b->addShape($s, SWFBUTTON_HIT | SWFBUTTON_DOWN | SWFBUTTON_OVER | SWFBUTTON_UP);
Note that this adds the same shape to all of the states, which means that the clickable area is the same as the shape's drawn area and that the button looks the same when you've moused over it or clicked down on it- not much fun at all. The buttons in our example won't be monkey-buckets of fun, either, but we'll make a separate hit region:
// make a hit region for the button

$hit = new SWFShape();
$hit->setRightFill($hit->addFill(0,0,0));
$hit->movePenTo(-600, -30);
$hit->drawLine(1200, 0);
$hit->drawLine(0, 60);
$hit->drawLine(-1200, 0);
$hit->drawLine(0, -60);
Without this, the hit region would be the interior of the headline text only, which would just be weird. Now let's squeeze out those buttons:
for($i=0; $i<$count; ++$i)
{
  $t = new SWFText();
  $t->setFont($f);
  $t->setHeight(40);
  $t->setColor(0,0,0);
  $t->moveTo(-$f->getWidth($title[$i])*(40/1024)/2, 20);
  $t->addString($title[$i]);

  $b[$i] = new SWFButton();
  $b[$i]->addShape($hit, SWFBUTTON_HIT);
  $b[$i]->addShape($t, SWFBUTTON_OVER | SWFBUTTON_UP | SWFBUTTON_DOWN);
  $b[$i]->addAction(new SWFAction("getURL('$url[$i]','popup');"),
                    SWFBUTTON_MOUSEUP);
}
There's another object type we haven't seen before, the SWFAction. Since it's getting late, we won't go too far into actions other than mention that Flash has a bytecode engine which lets you do a lot of really swell dynamic action stuff, and Ming compiles c-like script code into Flash action bytecode. The getURL action above causes the browser to load the given url. For more details, see the Ming web site.

So now that we have our buttons built, let's animate them. These two files contain functions which perform various transitions between headlines:

include('infuncs.php');
include('outfuncs.php');
For instance, the following function from infuncs.php slides the button in from the left while fading from complete transparency to fully opaque:
function slideleftin($movie, $shape)
{
  $i = $movie->add($shape);

  for($j=0; $j<=20; ++$j)
  {
    $i->moveTo(600-($j-20)*($j-20), 30);
    $i->multColor(1.0, 1.0, 1.0, $j/20);
    $movie->nextFrame();
  }

  return $i;
}
All of the functions in infuncs.php take a movie and a shape as arguments, and return an instance of the shape in the movie. The functions in outfuncs.php take the movie, the shape, and the instance created by the in-function and make sure the canvas is empty when they return.

The functions are listed in the arrays $infuncs and $outfuncs, allowing us to add new transitions by simply creating a function and listing it in the proper array, without touching the main php code at all. Here's the final bit of code which performs the animation:

for($n=0; $n<4; ++$n)
{
  for($i=0; $i<$count; ++$i)
  {
    $infunc = $infuncs[rand(0, count($infuncs)-1)];
    $instance = $infunc($m, $b[$i]);

    for($j=0; $j<60; ++$j)
      $m->nextFrame();

    $outfunc = $outfuncs[rand(0, count($outfuncs)-1)];
    $outfunc($m, $b[$i], $instance);
  }
}

header("Content-type: application/x-shockwave-flash");
$m->output();
We loop through it four times so that we can get a bit of variety, since just once usually misses a few of the transition effects.

Here's the source: .tgz - .zip

And thanks to Urs Gehrig, is also deals with .rss files now! Woohoo!


A tearful farewell

And now our time together has come to an end- I'll return to the carpal tunnel trauma ward and you'll spend the next three hours reading user comments on slashdot. But before you do, go to the Ming home page to learn more about Ming and download the code and see lots more examples and join the mailing lists and did I mention download the code?

-Dave

by the way,
Macromedia(r) and Flash(tm) are trademarks or registered trademarks of Macromedia, Inc. in the United States and/or other countries.
Macromedia(r) does not sponsor, affiliate, or endorse this product and/or services.