formatowanie liczb w actionscript, cz.2

Przyjrzawszy się po raz drugi problemowi, popełniłem poniższą metodę, zastępując poprzednią.
Trochę inne podejście, wszystko objaśnione w kodzie. Dla dobra publicznego publikuję:

		/**
		 * metoda formatuje liczbę z dokładnością zadaną przez @resolution,
		 * oddzielając tysiące znakiem z @thouSep a część ułamkową znakiem
		 * z @decPoint. Na końcu dodaje jednostkę @unit
		 * Np.:
		 * Format.Number(123.456, ' zł', 0.1) zwraca '123,5 zł'
		 * Format.Number(123.456, ' zł', 1) zwraca '123 zł'
		 * Format.Number(123.456, ' m', 10) zwraca '120 m'
		 */
		public static function number(
			v:			Number,
			unit:		String = '',
			resolution:	Number = 1,
			decPoint:	String = ',',
			thouSep:	String = ' '
		):String
		{
			var r:		String = '';
			var rDec:	String = '';
			var rInt:	String = '';
			var i:		int;
			var rIntTmp:String;
			var len: 	int;

			v = Math.round(v / resolution) * resolution;
			r = v.toString();
			// pozycja kropki dziesiętnej
			var decPointPos:int = r.lastIndexOf('.');

			// część całkowita
			if(decPointPos > -1)
				rIntTmp	= r.substr(0, decPointPos);
			else
				rIntTmp = r;

			len	= rIntTmp.length;
			// przepisujemy po 3 cyfry, dodając separator
			while(len > 3){
				rInt = thouSep + rIntTmp.substr(len - 3, len) + rInt;
				rIntTmp = rIntTmp.substr(0, len - 3);
				len = rIntTmp.length;
			}
			rInt = rIntTmp + rInt;

			// część ułamkowa
			if(resolution < 1) {
				// liczba znaków w części ułamkowej powinna być taka jak długość części ułamkowej @resolution
				var decLength = (resolution - Math.floor(resolution)).toString().length - 2;
				// część ułamkowa
				if(decPointPos > -1){
					var x:int = decPointPos + 1 + decLength;
					rDec = r.substring(decPointPos + 1, decPointPos + 1 + decLength);
				}
				// dodajemy zera na końcu, jeśli trzeba
				var zerosCount:int = decLength - rDec.length;
				for(i = 0; i < zerosCount; i++) rDec += '0';
				rDec = decPoint + rDec;
			}
			r = rInt + rDec + unit;
			return r;
		}

wielokolumnowy układ tekstu w actionscript

Jest taki przykład w dokumentacji Flexa, jest też trochę o tym na blogu niejakiego Daniela. Jednak oba przykłady kończą się tam, gdzie zaczyna się próba przelewania HTMLa przez kilka ramek tekstowych. Dla zwykłego, czystego tekstu to proste – zobaczyć ile się nie zmieściło w ramce n i wlać to do ramki n+1, aż do ostatniej ramki albo końca tekstu.

W przypadku HTMLa jednak Flash nas nie oszczędza. Obliczenie pozycji, na której powinien nastąpić podział jest skomplikowane, bo trzeba uwzględnić – niewidoczne w ramce – tagi, w dodatku pamiętać o automatycznym zamykaniu ich i otwieraniu w kolejnych ramkach. Metody klasy TextField jak getLineOffset() zwracają pozycję w czystym tekście, a podział musi nastąpić w odpowiadającym jej miejscu HTMLa. Na dokładkę HTML, jaki naprawdę jest w obiekcie TextField zupełnie niekoniecznie przypomina ten, który przypisaliśmy do htmlText! Dlatego trzeba najpierw wlać tekst do ramki:

naszTextField.htmlText = nowyHtml;

potem pobrać go do zmiennej i dalej pracować już nad nim:

processedHtml = naszTextField.htmlText;

a oto procedurka przelewająca:

protected function flow():void
{
var lastSplit:                int     = 0;
var newSplit:                int     = 0;
var tb:                        VTextBox;
var tbNum:                    int        = linkedTextBoxes.length;
var tagsHeap:                Array      = new Array();
var opening:                String;
var closing:                String;
var tempText:                String;
var remainder:                String;
var remainLinesNum:            int;
var lastVisibleLineIndex:    int;
var cutIndex:                int;

// liczba stron, na jaką trzeba będzie podzielić tekst
pagesNum             = 0;
// pozycje podziału stron
splitIndices         = new Array();
splitIndices.push(0);
// pozostała do wlania część tekstu – najpierw cały
remainder = processedText;
textPieces = new Array();

while(remainder.length > 0) {
textPieces[pagesNum] = new Array();
for(var i:int = 0; i < tbNum; i++) {
// kolejna ramka tekstowa
tb = linkedTextBoxes[i];
trace(‘strona ‘ + pagesNum + ‘, box nr ‘ + i);

// Jeśli tekst już się skończył, kolejne ramki bieżącej strony wypełniamy pustym tekstem.
// Jeśli tekst jeszcze jest, wlewamy pozostałą część i badamy ile się zmieściło
if(remainder.length == 0) {
textPieces[pagesNum][i] = ”;
} else {
// dodajemy na początek otwarcie wszystkich tagów kontynuowanych z poprzedniej ramki
opening                 = Html.getOpeningHtml(tagsHeap);
// wlewamy cały pozostały tekst
tb.htmlText             = opening + remainder;
// obliczamy, ile linii jest poza ramką
remainLinesNum             = tb.maxScrollV – 1;
trace(‘poza ramką jest linii: ‘ + remainLinesNum);

if(remainLinesNum == 0) {
textPieces[pagesNum][i] = opening + remainder;
remainder = ”;
} else {
// obliczamy index ostatniej linii
lastVisibleLineIndex     = tb.numLines – remainLinesNum – 1;
trace(‘indeks ostatniej linii: ‘ + lastVisibleLineIndex);
// pobieramy indeks ostatniego widocznego znaku
cutIndex                 = tb.getLineOffset(lastVisibleLineIndex) + tb.getLineLength(lastVisibleLineIndex) – 1;
trace(‘cutIndex: ‘ + cutIndex);
trace(‘cut rigth after …’ + tb.getLineText(lastVisibleLineIndex));
// pozostawiamy tylko mieszczącą się część tekstu
tempText                = remainder.substring(0, cutIndex);
remainder                = remainder.substr(cutIndex);
// uzupełniamy listę otwartych tagów
tagsHeap                 = Html.getTags(tempText, tagsHeap);
// pobieramy tagi do zamknięcia w ramce
closing = Html.getClosingHtml(tagsHeap);
textPieces[pagesNum][i] = opening + tempText + closing;
}
}
}
pagesNum++;
}

displayPage(0);
}

A oto link do video, w świetle którego całe powyższe rozważanie wkrótce straci sens.

osadzanie czcionek we Flashu i formatowanie tekstów (bold/italic)

A oto błąd we Flash CS3: kiedy wstawimy sobie dynamiczne pole tekstowe i zaszyjemy czcionki, postępując całkiem przepisowo, możemy doznać przykrego zaskoczenia. Jeśli np. lubimy napisy rozstrzelone i pogrubione jednocześnie, pewnie ustawiliśmy odstępy między literami na więcej niż 0, no i mamy zaznaczone wytłuszczenie. Może nawet pamiętaliśmy o stworzeniu czcionki w bibliotece i wybraliśmy ją dla naszego TextFielda. Cóż, kiedy rezultat będzie nieco inny niż zamierzony… Flash zgubi pogrubienie! Czcionka niby jest zaszyta, tekst jest widoczny po maskowaniu i obróceniu, ale nie jest wytłuszczony. Będzie tak, jeśli tworzymy obiekt zawierający to pole tekstowe dynamicznie (np. var a:Naszobiekt = new NaszObiekt();) Jaka rada? Ano, odpuścić kerning na 0 w edytorze CS3, a ustawić go w ActionScriptcie:

var tf:TextFormat;
tf = label_tf.defaultTextFormat;
tf.letterSpacing = 1.5;
label_tf.defaultTextFormat = tf;

Opcje istotne przy osadzaniu czcionki dla dynamicznego pola tekstowego we Flash CS3