Archive for May, 2006

Zooming & centering using Flash’s annoying ScrollPane

May 11, 2006

In the old Flash (the first version of MX) the FScrollPane component had a nice setScrollPosition function, with which one could set the position of the movie clip inside. This function no longer exists in the whizzy Flash 8 environment; it’s been replaced with ScrollPane, which has a much more obscure functionality, with the properties hPosition and vPosition. The documentation for hPosition states:

Property; the pixel position of the scroll pane’s horizontal scroll box (thumb). The 0 position is at the extreme left end of the scroll track, which causes the left edge of the scroll pane content to be visible in the scroll pane.

Liars! It’s nothing of the sort. hPosition does not descibe the scroll bars, it describes the horizontal position of the movieclip inside the pane; it is the amount the top-left corner of the clip is displaced to the left of the top-left corner of the pane. This is slightly confusing: Flash works on a rightwards-positive co-ordinate system, yet hPosition is always positive. Similarly, vPosition described displacement upwards, not downwards.

Anyway, with that confusion over, we can get something done. Let’s say we’re zooming into the clip by doubling its size, but we want to keep the display currently centered upon where we are. In the co-ordinate space of the movie clip (not the pane), where (0,0) is the top left corner of the clip, and the clip is currently displaced to the left by hPosition, then the x co-ordinate of the centre of the pane XC can be found by:

XC = hPosition + pane_mc.width/2

Doubling the clip in size will result in the co-ordinate of the new centre XC’ being twice that of the original. So we need to find the new displacement hPosition’

XC’ = 2XC
hPosition’ + pane_mc.width/2 = 2*(hPosition + pane_mc.width/2)
hPosition’ = 2*hPosition + pane_mc.width/2

Which means the following code will successfully zoom & center our clip:

// Scale our object
clip._xscale *= 2;
clip._yscale *= 2;

// New offset
var hPos = 2*scrollPane.hPosition + scrollPane.width/2;
var vPos = 2*scrollPane.vPosition + scrollPane.height/2;

// Refresh the pane to auto-add scrollbars
scrollPane.setSize(scrollPane.width, scrollPane.height);

// Set the new positions
scrollPane.hPosition = hPos;
scrollPane.vPosition = vPos;

You’ll need some extra code to deal with the clip not shifting outside the pane when you zoom back out again (which can happen) but this is trivial checking of bounds. Now you can use Flash’s ScrollPane to display zoomable clips (such as maps…)

Advertisements

Ming and version numbers

May 3, 2006

Ming has an obscure and not very well-documented function Ming_useSWFVersion() which can come in handy. In Ming 0.4.0, it defaults to Flash 5 SWF. This means if you want to add Flash 6+ functionality to your created SWF (e.g. you want to incorporate an onRollOver event function on an SWFSprite) from externally, it will not react. However, you can use the above function to set the version, e.g. (in Python, as always):

import ming
ming.Ming_useSWFVersion(6)

However, this creates what surely must be a bug. If you try adding code to a SWFSprite that uses the keyword this then the Ming ActionScript compiler throws an error, saying it does not recognise it. For me, this code does not work:

my_mc.add(SWFAction("this.onRelease = function() { trace('foo'); };"))

Luckily, I think you can miss out the this without too much worry, as Flash’s scoping usually picks up local variables first. If you really need it, you can always use eval to do:

my_mc.add(SWFAction(
  "t = eval('this'); t.onRelease = function() { trace('foo'); };"
  ))

and this compiles satisfactorily.

Remember to use nextFrame() when adding code and shapes to SWFSprites

May 2, 2006

In Ming, when working with SWFSprite objects (i.e. Flash MovieClips), you will often want to add in code and shape data to the sprite. When doing so, remember to “commit” the additions you make by calling nextFrame(), else nothing will appear. So, in Python, you would do something like:

clip = SWFMovie()
clip_shape = SWFShape()
clip_action = SWFAction("this.foo = bar;")
clip.add(clip_action)
clip.add(clip_shape)
clip.nextFrame()

Thus the additions get properly “saved” into the object. This potential pitfall is also covered on page 4 of the Ming tutorial but it doesn’t hurt to have it written down twice.