Опубликован: 23.12.2005 | Уровень: специалист | Доступ: платный | ВУЗ: Московский физико-технический институт
Лекция 10:

Программное рисование во Flash MX

< Лекция 9 || Лекция 10: 123456 || Лекция 11 >

Рассмотрим теперь градиент с матрицей вида типа " box ": {matrixType, w, h, x, y, r}. На первый взгляд может показаться, что поля такого объекта похожи на параметры матрицы 10.16, но это не совсем так. Матрица преобразования для такого градиента имеет вид:


Преобразования, соответствующие этой матрице, следующие: сначала - сдвиг по x и по y на 0.5 (то есть, левый верхний угол прямоугольника, содержащего градиент, оказывается в точке (0, 0)), затем поворот на угол r (в радианах), затем растяжение по x в w и по y в h раз. Это преобразование отличается от преобразования по матрице 10.16 наличием сдвига на 0.5 по х и y, а главное - порядком операций поворота и масштабирования. И эта разница существенна. Так, если выполнять преобразование 10.19 для радиального градиента, то поворот осуществляется тогда, когда градиент еще имеет радиальную симметрию, а значит его форма при повороте не меняется. То есть, с помощью такого преобразования мы можем получить только эллипс с осями, параллельными осям координат (рис. 10.13). Расположение линейного градиента при таком способе задания оказывается трудно предсказуемым (кроме самых простых случаев, когда r = 0 или w = h ).


Рис. 10.15.

Результат выполнения метода beginGradientFill с аргументом matrix = {matrixType: "box", w: 130, h:60, x: 0, y: 0, r: Math.PI/180*20}

Как было сказано выше, с помощью одного оператора beginGradientFill во FlashMX можно получить только эллиптический или линейный градиент. Однако если наложить друг на друга несколько градиентов с изменением прозрачности, то можно получить переход цвета довольно сложной формы. Один из таких вариантов рассмотрен в примере 10.14.

outlineSqr = function(){
	moveTo(-100, -100);
	lineTo(100, -100);
	lineTo(100, 100);
	lineTo(-100, 100);
	lineTo(-100, -100);
}
beginFill(0, 100);
outlineSqr();
endFill();
beginGradientFill("linear",
[0xffffff,0xffffff, 0xfffffff],
[100, 0, 100],
	[0, 0x7f, 0xFF],
	{a: 200, b: 0, d: 0, e: 200, g: 0, h:0});
outlineSqr();
endFill();
beginGradientFill("linear",
	[0xffffff,0xffffff, 0xfffffff],
	[100, 0, 100],
	[0, 0x7f, 0xFF],
	{a: 0, b: 200, d: -200, e: 0, g: 0, h:0});
outlineSqr();
endFill();
10.14.
Результат выполнения кода из примера 10.14

Рис. 10.16. Результат выполнения кода из примера 10.14

Примеров практического применения программно нарисованной градиентной заливки может быть много. Приведем здесь один из них: динамический градиент удобно использовать, если нужно размыть края произвольной картинки плавным переходом в цвет фона. Сделать это можно несколькими способами. Самый простой из них описан в примере 10.15.

makeFeatherFrame = function(target_mc, width, color){
	boundRect=target_mc.getBounds();
	targDepth = getMaxFreeDepth(target_mc);
	frName = target_mc._name + "_frame";
	target_mc.createEmptyMovieClip(frName, targDepth);
	frame_mc = target_mc[frname];
	frame_mc._x = boundRect.xMin;
	frame_mc._y = boundRect.yMin;
	W = boundRect.xMax - boundRect.xMin;
	H = boundRect.yMax - boundRect.yMin;
	relHorWidth = 0xFF * width / W;
	relVerWidth = 0xFF * width / H;
	colors = [color, color, color, color];
	alphas = [100, 0, 0, 100];
	horRatios = [0, relHorWidth, 0xFF - relHorWidth, 0xFF];
	verRatios = [0, relVerWidth, 0xFF - relVerWidth, 0xFF];
	horMatrix = {a: W, b: 0, d: 0, e: H, g: W/2, h: H/2};
	verMatrix = {a: 0, b: H, d: -W, e: 0, g: W/2, h: H/2};
	frame_mc.beginGradientFill("linear", colors, alphas, 
		horRatios, horMatrix);
	outlineRect(frame_mc, 0, 0, W, H);
	frame_mc.endFill();
	frame_mc.beginGradientFill("linear", colors, alphas, 
		verRatios, verMatrix);
	outlineRect(frame_mc, 0, 0, W, H);
	frame_mc.endFill();
	
}
getMaxFreeDepth = function(target_mc){
	var mfd = 0;
	for (in_mc in target_mc){
		if (typeof(target_mc[in_mc])=="movieclip" 
&& target_mc[in_mc].getDepth() > mfd) 
			mfd = target_mc[in_mc].getDepth();
	}
	return mfd + 1;
}
outlineRect = function(target_mc, xMin, yMin, xMax, yMax){
	target_mc.moveTo(xMin, yMin);
	target_mc.lineTo(xMin, yMax);
	target_mc.lineTo(xMax, yMax);
	target_mc.lineTo(xMax, yMin);
	target_mc.lineTo(xMin, yMin);
}
makeFeatherFrame(photo_mc, 30, 0xffffff);
10.15.
Результат выполнения кода из примера 10.15

Рис. 10.17. Результат выполнения кода из примера 10.15

На этом примере обнаруживается еще одно ограничение динамического градиента: пространство между крайними цветами градиента делится на 255 (0xFF) частей, и каждая часть заливается сплошным цветом. И чем шире градиент, тем шире - а следовательно заметнее - каждая полоска. Так что на краях фотографии, показанной на рисунке 10.17, можно заметить, что цвет фотографии в цвет фона переходит не плавно, особенно на правой и левой границах. Чтобы этого избежать, можно делать градиентную заливку не на всей ширине клипа, а только на границах. Это, однако, увеличивает количество кода (пример 10.16).

makeStrictFeatherFrame = function(target_mc, width, color){
boundRect=target_mc.getBounds();
// метод getMaxFreeDepht описан в предыдущем примере
targDepth = getMaxFreeDepth(target_mc); 
frName = target_mc._name + "_frame";
target_mc.createEmptyMovieClip(frName, targDepth);
frame_mc = target_mc[frname];
frame_mc._x = boundRect.xMin;
frame_mc._y = boundRect.yMin;
W = boundRect.xMax - boundRect.xMin;
H = boundRect.yMax - boundRect.yMin;
colors = [color, color];
alphas = [100, 0];
ratios = [0, 0xFF];
lMatrix = {a: width, b: 0, d: 0, e: 100, g: width/2, h: H/2};
tMatrix = {a: 0, b: width, d: -100, e: 0, g: W/2, h: width/2};
rMatrix = {a: -width, b: 0, d: 0, e: -100, g: W - width/2, h: H/2};
bMatrix = {a: 0, b: -width, d: 100, e: 0, g: W/2, h: H - width/2};
with (frame_mc){
	beginGradientFill("linear", colors, alphas, ratios, lMatrix);
	//метод outlineRect описан в предыдущем примере
	outlineRect(frame_mc, 0, 0, width, H);
	endFill();
	beginGradientFill("linear", colors, alphas, ratios, tMatrix);
	outlineRect(frame_mc, 0, 0, W, width);
	endFill();
	beginGradientFill("linear", colors, alphas, ratios, rMatrix);
	outlineRect(frame_mc, W-width, 0, W, H);
	endFill();
	beginGradientFill("linear", colors, alphas, ratios, bMatrix);
		outlineRect(frame_mc, 0, H-width, W, H);
		endFill();
	}
	
}
makeStrictFeatherFrame(photo_mc, 30, 0xffffff);
10.16.
Результат выполнения кода из примера 10.16

Рис. 10.18. Результат выполнения кода из примера 10.16

В примере 10.16 расстояние, на котором происходит переход одного цвета в другой, определяется толщиной рамки, так что на рис. 10.18 дискретность градиента не заметна. Однако если приглядеться к углам фотографии, они могут показаться все еще неудовлетворительными: в каждом углу наблюдается картинка, похожая на рис. 10.14. Чтобы этого избежать, можно дополнить линейные градиенты по сторонам фотографии радиальными в ее углах (пример 10.17).

makeStrictRoundedFeatherFrame = function(target_mc, width, color){
boundRect=target_mc.getBounds();
targDepth = getMaxFreeDepth(target_mc);
frName = target_mc._name + "_frame";
target_mc.createEmptyMovieClip(frName, targDepth);
frame_mc = target_mc[frname];
frame_mc._x = boundRect.xMin;
frame_mc._y = boundRect.yMin;
W = boundRect.xMax - boundRect.xMin;
H = boundRect.yMax - boundRect.yMin;
colors = [color, color];
alphas = [0, 100];
ratios = [0, 0xFF];
lMatrix = {a: -width, b: 0, d: 0, e: 100, g: width/2, h: H/2};
tMatrix = {a: 0, b: -width, d: -100, e: 0, g: W/2, h: width/2};
rMatrix = {a: width, b: 0, d: 0, e: -100, g: W - width/2, h: H/2};
bMatrix = {a: 0, b: width, d: 100, e: 0, g: W/2, h: H - width/2};
ltMatrix = {a: 2*width, b: 0, d: 0, e: 2*width, g: width, h: width};
rtMatrix = {a: 2*width, b: 0, d: 0, e: 2*width, g: W-width, h: width};
rbMatrix = {a: 2*width, b: 0, d: 0, e: 2*width, g: W-width, 
h: H-width};
lbMatrix = {a: 2*width, b: 0, d: 0, e: 2*width, g: width, 
h: H-width};
with (frame_mc){
	beginGradientFill("linear", colors, alphas, ratios, lMatrix);
	outlineRect(frame_mc, 0, width, width, H-width);
	endFill();
	beginGradientFill("linear", colors, alphas, ratios, tMatrix);
	outlineRect(frame_mc, width, 0, W-width, width);
	endFill();
	beginGradientFill("linear", colors, alphas, ratios, rMatrix);
	outlineRect(frame_mc, W-width, width, W, H-width);
	endFill();
	beginGradientFill("linear", colors, alphas, ratios, bMatrix);
	outlineRect(frame_mc, width, H-width, W-width, H);
	endFill();
	beginGradientFill("radial", colors, alphas, ratios, ltMatrix);
	outlineRect(frame_mc, 0, 0, width, width);
	endFill();
	beginGradientFill("radial", colors, alphas, ratios, rtMatrix);
	outlineRect(frame_mc, W-width, 0, W, width);
	endFill();
	beginGradientFill("radial", colors, alphas, ratios, rbMatrix);
	outlineRect(frame_mc, W-width, H-width, W, H);
	endFill();
	beginGradientFill("radial", colors, alphas, ratios, lbMatrix);
	outlineRect(frame_mc, 0, H-width, width, H);
	endFill();
	}
}
10.17.
Результат выполнения кода из примера 10.17

Рис. 10.19. Результат выполнения кода из примера 10.17

Граница фотографии на рис. 10.19 выглядит вполне аккуратно, однако количество кода в примере 10.17 еще больше.

Градиент типа " radial " можно использовать для получения овальной рамки (пример 10.18).

makeOvalFrame = function(target_mc, width, color){
	boundRect=target_mc.getBounds(target_mc._parent);
	targDepth = target_mc.getDepth();
	frName = target_mc._name + "_frame";
	target_mc._parent.createEmptyMovieClip(frName, targDepth+1);
	frame_mc = target_mc._parent[frname];
	frame_mc._x = boundRect.xMin;
	frame_mc._y = boundRect.yMin;
	W = boundRect.xMax - boundRect.xMin;
	H = boundRect.yMax - boundRect.yMin;
	relWidth = 2*0xFF * width / Math.max(W, H);
	colors = [color, color, color];
	alphas = [0, 0, 100];
	ratios = [0, 0xFF - relWidth, 0xFF];
	matrix = {a: W, b: 0, d: 0, e: H, g: W/2, h: H/2};
	frame_mc.beginGradientFill("radial", colors, alphas, ratios, matrix);
	outlineRect(frame_mc, 0, 0, W, H);
	frame_mc.endFill();
	
}
10.18.
Результат выполнения кода из примера 10.18

Рис. 10.20. Результат выполнения кода из примера 10.18
< Лекция 9 || Лекция 10: 123456 || Лекция 11 >
алексеи федорович
алексеи федорович
Беларусь, рогачёв
Тамара Ионова
Тамара Ионова
Россия, Нижний Новгород, НГПУ, 2009