Friday, November 9, 2012

Creating EasyTooltip class: Part 8

In this tutorial we will improve the auto-sizing algorithm by calculating the best direction in which the tooltip will be displayed, relative to the mouse.

Go to TooltipCursor class and declare a new variable "direction":

private var direction:String = "";

In the updateSize() function we shall calcualte which direction the tooltip should be casted, relative to the mouse of the user. This is done in order to display as much content as possible, therefore - the tooltip is casted in the direction, which has more free space for it.

Right now we are going to add only 2 directions - topright and topleft. The algorithm behind it is actually fairly simple - all we do is check in which half of the parent (stage in this case) the mouse is located. If mouse is in the left half of the parent, then there is more space on the right - so the direction will be "topright", and vice versa.

Other than just setting the direction values, we will also set actual_x and actual_y values. For topright, we keep them as they were before, but for topleft - move them to the left by X pixels, where X is the width of the tooltip.

// calculate best direction
if (this.x <= parentW * 0.5) { 
direction = "topright"; 
actual_x = 0 + style.offsetX;
actual_y = -h + style.offsetY;
} else
if (this.x > parentW * 0.5) { 
direction = "topleft";
actual_x = -w + style.offsetX;
actual_y = -h + style.offsetY;
}

The code we had after this remains the same, except that we execute it only if direction is topright. Also, instead of adding 4 pixels in the while loop - add just 1 (for more precision):

// If sticks out on the left:
if(direction == "topright"){
// if tooltip sticks out of border - calculate shortened width to fit the content
if (this.x + actual_x + w > parentW) {
txt.wordWrap = true;
w = parentW - this.x - actual_x;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;
} else {
// if doesn't stick out, keep adding 1 pixel to the width until as much text is seen as possible
while (this.x + actual_x + w < parentW) {
w += 1;
// try turning off wordwrap and see if it still fits (as one line)
txt.wordWrap = false;
if (w > txt.textWidth + 4 + style.textPadding.left + style.textPadding.right) {
w = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
break;
}
txt.wordWrap = true;
}
}
}

If direction is topleft, the code is similar, yet some values need to be changed.

Take a look:

// If sticks out on the right:
if(direction == "topleft"){
if (this.x + actual_x <= 0) {
txt.wordWrap = true;
actual_x = -this.x;
w = this.x;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;
} else {
// if doesn't stick out, keep adding 1 pixel to the width (and substracting it from actual_x) until as much text is seen as possible
while (this.x + actual_x > 0) {
actual_x -= 1;
w += 1;
// try turning off wordwrap and see if it still fits (as one line)
txt.wordWrap = false;
if (w > txt.textWidth + 4 + style.textPadding.left + style.textPadding.right) {
w = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
break;
}
txt.wordWrap = true; 
}
}
}

Full class code:

package com.kircode.EasyTooltip 
{
import flash.display.MovieClip;
import flash.display.Shape;
import flash.text.TextField;
import flash.text.TextFormat;
/**
 * The cursor that follows the mouse (if not set otherwise) and displays each tooltip.
 * @author Kirill Poletaev
 */
public class TooltipCursor extends MovieClip
{

public var txt:TextField;
private var style:TooltipStyle;
private var background:Shape;
private var w:int;
private var h:int;
private var actual_x:int;
private var actual_y:int;
private var parentW:int;
private var parentH:int;
private var direction:String = "";

public function TooltipCursor(pW:int, pH:int) 
{
parentW = pW;
parentH = pH;
txt = new TextField();
txt.multiline = true;
background = new Shape();
addChild(background);
addChild(txt);
}

/**
 * Set style of the tooltips.
 * @paramst TooltipStyle object to apply.
 */

public function setStyle(st:TooltipStyle):void {
style = st;
}

/**
 * Change the text value of the tooltip.
 * @parammessage The new text value.
 */

public function setText(message:String):void {
txt.text = message;
txt.setTextFormat(style.textFormat);
updateSize();
updateDisplay();
}

private function updateDisplay():void {
background.graphics.clear();
background.graphics.beginFill(style.backgroundColor, style.backgroundAlpha);
background.graphics.drawRect(actual_x, actual_y, w, h);
background.graphics.endFill();

txt.width = w - style.textPadding.left - style.textPadding.right;
txt.height = h - style.textPadding.top - style.textPadding.bottom;
txt.x = actual_x + style.textPadding.left;
txt.y = actual_y + style.textPadding.top;
}

private function updateSize():void {
w = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;

// calculate best direction
if (this.x <= parentW * 0.5) { 
direction = "topright"; 
actual_x = 0 + style.offsetX;
actual_y = -h + style.offsetY;
} else
if (this.x > parentW * 0.5) { 
direction = "topleft";
actual_x = -w + style.offsetX;
actual_y = -h + style.offsetY;
}

// If sticks out on the left:
if(direction == "topright"){
// if tooltip sticks out of border - calculate shortened width to fit the content
if (this.x + actual_x + w > parentW) {
txt.wordWrap = true;
w = parentW - this.x - actual_x;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;
} else {
// if doesn't stick out, keep adding 1 pixel to the width until as much text is seen as possible
while (this.x + actual_x + w < parentW) {
w += 1;
// try turning off wordwrap and see if it still fits (as one line)
txt.wordWrap = false;
if (w > txt.textWidth + 4 + style.textPadding.left + style.textPadding.right) {
w = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
break;
}
txt.wordWrap = true;
}
}
}

// If sticks out on the right:
if(direction == "topleft"){
if (this.x + actual_x <= 0) {
txt.wordWrap = true;
actual_x = -this.x;
w = this.x;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;
} else {
// if doesn't stick out, keep adding 1 pixel to the width (and substracting it from actual_x) until as much text is seen as possible
while (this.x + actual_x > 0) {
actual_x -= 1;
w += 1;
// try turning off wordwrap and see if it still fits (as one line)
txt.wordWrap = false;
if (w > txt.textWidth + 4 + style.textPadding.left + style.textPadding.right) {
w = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
break;
}
txt.wordWrap = true; 
}
}
}

}

}

}

Thanks for reading!

Here are the results so far:


No comments:

Post a Comment