Skip to main content
Inspiring
September 18, 2009
Question

Background images on block elements

  • September 18, 2009
  • 1 reply
  • 924 views

I would like to replicate some HTML functionality using TLF.

I want to create divs with background images.

The image would be scaled, cropped or tiled to fit the bounds of the div.

I want to have multiple divs, and be able to select across them.

I may end up with thousands of these and be able to delete some from the top of the stack to keep performance up.

Would I have to have a whole separate class to map sprites with the bg images to divs, each time the TextFlow is updated?

Or would I be best to extend the div element to have a background image property?

Or is there a different way to do this? Perhaps, there is a way to bind sections of text to specific containers and have the scale to accomodate the text?

This topic has been closed for replies.

1 reply

Adobe Employee
September 21, 2009

Interesting problem! I will try breaking it up into pieces. I think you will need to do the following:

(1) Associate an image with the div.

(2) Figure out after composition how much space is taken by the div

(3) At draw time, scale the image, place it at the correct location, and make it a child of the container.

The first step is not too hard. You can use the FlowElement's userStyles property and create a dictionary that relates the "name" of your property (e.g. "backgroundImage" with the Image or DisplayObject).

The second step is a little harder. If you want this to work across multiple containers, you should consider that when you do your coding -- it's a little extra work. There's an example, ParagraphBorders.as, in our example code set (this may be on the Labs website now, and not with the other open source code). I think this might serve as starting point. Basically, it finds the lines associated with the paragraph element, and derives the geometry from the TextLines.  Here's an excerpt:

    private function paragraphBBox(p:ParagraphElement):Rectangle
        {
            var bbox:Rectangle = new Rectangle();
             var pos:int = p.getAbsoluteStart();
            var endPos:int = pos + p.textLength;
             while (pos < endPos)
             {
                 var line:TextFlowLine = p.getTextFlow().flowComposer.findLineAtPosition(pos);
                 bbox = bbox.union(line.getTextLine().getBounds(this));
                 pos += line.textLength;
             }
             return bbox;
        }

The easiest thing to do might be to override the ContainerController with your own controller, and run this code as part of a controller update. It could figure out the space required, do the scaling, and then attach the image as a child of the container.

That's a quick sketch of how you might go about this. Hope this helps!

- robin

josh_onAuthor
Inspiring
September 23, 2009

Thanks Robin,

that was very helpful.  I have the basics working - now I have to tweak and optimize - (please see my latest post!)

I extended the ContainerController Class and over-rid the updateCompositionShapes - for now calling super and then cycling through visible divs and appending background, and deleting ones which are no longer in the visible scroll area of the container.

I have some questions about optimizing this - but I think they may be answered when I solve the question I posed about auto cscroll optimization.  But I do have a question specifically about div backgrounds.

I found it very hard to have all the backgrounds sit flush against one another, they pretty much do now but I had to add a constant to the ypos to have the bgs aligned with the text, here is my function - if you can see a nicer way of doing this I would be thankful:

protected function getDivBounds(d:DivElement):Rectangle {

            var pos:int = d.getAbsoluteStart();

            var endPos:int = pos + d.textLength;

            var line:TextFlowLine = d.getTextFlow().flowComposer.findLineAtPosition(pos);

            var x:Number = 0;

            var y:Number = line.y - line.ascent + line.descent + 5; // why does this work like this?

            var w:Number = container.width; // I want the bgs to span the full container

            var h:Number = 0;

            // loop over the lines of the div

             while (pos < endPos)

             {

                 line = d.getTextFlow().flowComposer.findLineAtPosition(pos);

                 h += line.height + line.spaceAfter + line.spaceBefore;

                 pos += line.textLength;

             }

             return new Rectangle(x, y, w, h);

       }

thanks,

Josh

Adobe Employee
September 23, 2009

Lines are sequential.  You could save some work by calling findLineIndexAtPosition for the startPos, using the return value as a parameter to getLineAt and then incrementing until you reached the line ending at endPos.

Richard