2

I got a issue with the TLF trying to find the position of an element (e.g. LinkElement), before it is added to the display list.

I tried the following code:

  1. Create my textFlow:

    var textFlow:TextFlow = TextConverter.importToFlow(MY_HTML_STRING,
    TextConverter.TEXT_FIELD_HTML_FORMAT);
    
  2. Grab all the Element I need:

    var lElem:Array = findLinkElement(textFlow, []);
    
    private function findLinkElement(group:FlowGroupElement, arr:Array):Array {
        var childGroups:Array = [];
        for (var i:int = 0; i < group.numChildren; i++) {
            var element:FlowElement = group.getChildAt(i);
            if (element is LinkElement) {
                arr.push(element as LinkElement);
            } else if (element is FlowGroupElement) {
                childGroups.push(element);
            }
        }
    
        for (i = 0; i < childGroups.length; i++) {
            var childGroup:FlowGroupElement = childGroups[i];
            findLinkElement(childGroup, arr);               
        }
    
        return arr;
    }
    
  3. For each element found try to get the boundaries:

    for each (var le:LinkElement in lElem){
        var abs:int = le.getAbsoluteStart(); 
        var tl:TextLine = le.getTextFlow().flowComposer.getLineAt(abs).getTextLine(true);
        var rect:Rectangle = tl.getAtomBounds(tl.getAtomIndexAtCharIndex(abs));   
    }
    

It seems I can't retrieve the Textline because the flowComposer is null.

Any idea how I can get the boundaries / why the composer is always null?

poke
  • 307,619
  • 61
  • 472
  • 533
Guillaume
  • 59
  • 5

1 Answers1

1

The problem is not that the flowComposer is null. It's actually an object, but you've got such a long chain of objects in this expression and something else in that chain is null:

var tl:TextLine = le.getTextFlow().flowComposer.getLineAt(abs).getTextLine(true);

The issue is is that you are getting the character index of each LinkElement -- this is not the line number. So when you do flowComposer.getLineAt(abs) it's returning null because that line does not exist.

Instead, you want to use flowComposer.getLineAtPosition(abs). Also, as an optimization the entire flow may not have been generated. So before you do this, it is wise to call flowComposer.composeToPosition(abs).

Below is your code that I've modified to do the above. You may not need the composeToPosition() call, it could actually be a performance issue doing it many times inside of a loop. I'll leave that for you to decide.

Here's the code that I used (minus the declaration of my html variable). The pertinent code that I modified is inside that for each loop:

var container:Sprite = new Sprite;
stage.addChild(container);
var textFlow:TextFlow = TextConverter.importToFlow(html, TextConverter.TEXT_FIELD_HTML_FORMAT);
var controller:ContainerController = new ContainerController(container, 200,200);
textFlow.flowComposer.addController(controller);
textFlow.flowComposer.updateAllControllers();
var links:Array = findLinkElement(textFlow, []);

// modified this code
for each (var le:LinkElement in links){
    var abs:int = le.getAbsoluteStart(); 
    var composer:IFlowComposer = le.getTextFlow().flowComposer;
    composer.composeToPosition(abs);
    var textFlowLine:TextFlowLine = composer.findLineAtPosition(abs);
    var tl:TextLine = textFlowLine.getTextLine(true);
    var rect:Rectangle = tl.getAtomBounds(tl.getAtomIndexAtCharIndex(abs));   
}
Sunil D.
  • 17,539
  • 6
  • 48
  • 60
  • Thank you for you reply, I understand the problem. I tried you code but keep getting a RangeError: Error #2006: The supplied index is out of bounds. at flash.text.engine::TextLine/getAtomBounds() I tested with a dummy html string : var html:String = "dfdfdffdfsdfsdfsdfxcwxcxcwxcwxcq
    sdfsdfsdf";
    – Guillaume Feb 19 '13 at 13:56
  • The Range Error actually appears when the HTML is 'multi lined'. – Guillaume Feb 19 '13 at 14:01