Беларусь, рогачёв |
Программное рисование во Flash MX
Рассмотрим теперь градиент с матрицей вида типа " 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 ).
Результат выполнения метода 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.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.
На этом примере обнаруживается еще одно ограничение динамического градиента: пространство между крайними цветами градиента делится на 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.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.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.