» direct naar zoek en menu

Tijdschrift voor webwerkers » Artikel #94

Illustrator « » Flash - Interactieve illustraties

Het importeren van een Illustrator-bestand in Flash is een standaard functie. Het geïmporteerde Illustrator-bestand is binnen de uiteindelijke Flash animatie echter niet meer interactief aan te passen door de gebruiker.

In deze handleiding leg ik je uit hoe je een Illustrator-bestand naar Flash kunt vertalen met behulp van actionscript, waarbij de lijnen – Bézier-curves – net als in Adobe Illustrator interactief aan te passen zijn binnen de uiteindelijke Flash-animatie.

Bij het maken van deze handleiding heb ik geprobeerd de theorie zo eenvoudig mogelijk te houden, met het oog op de meer artistieke en minder technische lezer. In veel gevallen vormt techniek een belemmerende factor voor ontwerpers. Een ontwerper is vooral creatief en houdt geen rekening met technische beperkingen, omdat deze het ‘creatieve proces’ negatief zouden beïnvloeden. Door beide disciplines te combineren kun je tot resultaten komen die de meeste ontwerpers en techneuten laten liggen. Het is dus zeker de moeite waard om je in deze materie te verdiepen!

Inleiding

Het oorspronkelijk idee was om de controlepunten – ook wel handles, tangent points of nodes genoemd – zichtbaar te maken binnen een Illustrator afbeelding. Maar eerst moest ik natuurljk uitzoeken of het technisch haalbaar was. Na het bestuderen van de specificaties van het bestandsformaat .ai bleek dat het relatief eenvoudig was de informatie met betrekking tot de Bézier-curves uit het originele Adobe Illustrator-bestand te isoleren.

Het resultaat leverde de volgende afbeelding op:

De .gif afbeelding die ik van het Illustrator-bestand maakte, mailde ik o.a. naar Michiel Jelijs, voormalig collega, css, javascript en accessibility goeroe. Hij merkte op dat hij dacht dat de afbeelding interactief was. Een .gif bestand kan niet interactief zijn, waardoor ik deze opmerking niet helemaal kon plaatsen. De opmerking leidde bij mij echter wel tot de vraag of het niet mogelijk zou zijn om het geheel interactief te maken...

Vectoren en bitmaps

Computer graphics kun je opdelen in twee groepen, te weten vector graphics en bitmap graphics.

Een vector graphic bestaat uit een wiskundige beschrijving, in het geval van Adobe Illustrator Bézier-curves. Het grote voordeel van vector graphics is dat ze zonder kwaliteitsverlies schaalbaar zijn. Ook zijn ze relatief klein qua omvang ten opzichte van bitmap graphics. Nadeel is dat de vector graphic elke keer opnieuw berekend moet worden: de wiskundige beschrijvingen moeten naar een afbeelding vertaald worden. Dit kan vooral bij grote afbeeldingen een aanslag op de rekenkracht van je computer zijn.

Bitmap graphics bestaan uit een horizontaal en verticaal grid waarbij elk puntje – of pixel – in het grid een eigen kleurcode heeft. Voorbeelden van bitmap graphics zijn het bestandsformaat .gif, .jpg, .png. etc.

Opbouw Adobe Illustrator-bestand

Hoe zit zo'n Illustrator-bestand nou in elkaar? Een willekeurig bestand voor een specifiek programma heeft een vaste opbouw. De manier waarop informatie over bijvoorbeeld formaat, kleurgebruik, lettertypes etc. opgeslagen wordt is door de producent vastgelegd in een blauwdruk met specificaties. Deze specificaties worden gebruikt door ontwikkelaars van software en waarborgen uniformiteit. Een .gif afbeelding is hierdoor probleemloos te openen in bijvoorbeeld een webbrowser, of als texture-map te gebruiken in een 3d programma.

De informatie in een bestand is in de meeste gevallen zó opgeslagen dat het bestand bij het openen in een tekstverwerkingsprogramma een brei aan onleesbare karakters oplevert. Een Illustrator-bestand levert echter geen onleesbare brei aan karakters op: je kunt het probleemloos openen en ‘lezen’ in een tekstverwerker.

Voor dit voorbeeld exporteer ik het originele bestand naar een tijdelijke Adobe Illustrator versie 3.0 bestand. Dit levert namelijk een relatief klein bestand op, wat volstaat voor deze toepassing.

Een Illustrator-bestand kun je opdelen in drie delen, te weten de header, de content en een footer.

Het eerste deel van het bestand wordt gevormd door de header en bevat algemene informatie over de Adobe Illustrator-versie van het document, naam van het document, posities, kleurmodel etc.

De header kan er als volgt uitzien:

 %!PS-Adobe-3.0
 %%Creator:Adobe Illustrator(TM) 3.2
 %%For: arjan
 %%Title: naarvoren
 %%CreationDate: () ()
 %%BoundingBox: -200 -200 200 200
 %%DocumentProcessColors:
 %%DocumentNeededResources: procset Adobe_packedarray 2.0 0
 %%+ procset Adobe_cshow 1.1 0
 %%+ procset Adobe_customcolor 1.0 0
 %%+ procset Adobe_IllustratorA_AI3 1.0 1
 %AI3_ColorUsage: Color
 %%TemplateBox: -200 -200 200 200
 %%TileBox: -200 -200 200 200
 %AI3_DocumentPreview: None
 %%PageOrigin:300 300
 %%AI3_PaperRect:-12 730 583 -12
 %%AI3_Margin:12 -12 -12 12
 %AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9
 %AI9_Flatten: 1
 %%EndComments
 %%BeginProlog


De header eindig met de regel '%%EndSetup'. De regels die na '%%EndSetup' volgen vormen de content en de footer.

De content bevat de informatie met betrekking tot de Bézier-curves en is het enige deel van het Illustrator-bestand dat relevant is voor het maken van de interactieve Flash-Illustrator animatie.

Over de exacte betekenis van bijvoorbeeld GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 en vele andere cryptische codes hoef je je geen zorgen te maken: die zijn voor het maken van de animatie niet relevant.

Bézier-curves algemeen

Elke afbeelding die gemaakt is binnen Adobe Illustrator is opgebouwd uit Bézier-curves. De Bézier-curve is het basiselement binnen Adobe Illustrator, zoals de pixel het basiselement binnen bijvoorbeeld Photoshop is.

Een Bézier-curve is een curve die beschreven wordt met een relatief eenvoudige wiskundige formule. Deze is ontwikkeld door de Fransman Pierre Bézier in de jaren zestig. Oorspronkelijk is de beschrijving van de Bézier-curve ontwikkeld voor toepassing binnen CAD/CAM voor het ontwerpen van auto's en vliegtuigen. Naast CAD/CAM wordt de Bézier-curve ook veel gebruikt binnen computer graphics toepassingen zoals Adobe Illustrator, Macromedia Freehand, maxxon's cinema 4D etc.

Een Bézier-curve bestaat uit een begin- en eindpositie – ook wel anchor points genoemd – en één of twee controle punten, ook wel handles, tangent points, of nodes genoemd. De controlepunten beïnvloeden de kromming van de Bézier-curve.

Binnen Adobe Illustrator zijn er drie mogelijke Bézier-curves. De eerste mogelijkheid is eigenlijk geen Bézier-curve, maar een rechte lijn (zie afbeelding): hij bestaat uit een beginpositie en een eindpositie. De tweede en derde mogelijke Bézier-curves bestaan uit curves met één of twee controleposities (zie afbeelding). Een Bézier-curve met één controlepunt wordt een quadratic Bézier-curve genoemd, een Bézier-curve met twee controlepunten wordt een cubic Bézier-curve genoemd.

Benodigdheden

De uiteindelijke interactieve Flash-Illustrator animatie zal bestaan uit interactieve controlepunten, de begin- en eindposities van de Bézier-curves zijn niet interactief.

Waarom heb ik er voor gekozen om de begin- en eindposities van de Bézier-curves niet interactief te maken? Eigenlijk omdat dit de actionscriptcode complexer zou maken: wanneer begin- en eindposities van de Bézier-curves ook interactief worden, moet er een controle plaatsvinden of de betreffende positie bij één of meerdere Bézier-curves hoort. Bij een eventuele aanpassing van de begin- of eindpositie moeten de Bézier-curves die een bepaalde positie delen aangepast worden. Voor de Flash-Illustrator animatie heb ik de keuze gemaakt dit niet te doen.

Elk controlepunt is gekoppeld aan een afzondelijke Bézier-curve. Wanneer een controlepunt interactief aangepast wordt, is direct duidelijk welke Bézier-curve aangepast moet worden. De gebruiker kan slechts één controlepunt per keer aanpassen, waardoor de hoeveelheid berekeningen per aanpassing beperkt wordt tot het tekenen van één enkele Bézier-curve.

De illustratie in Flash wordt opgebouwd uit afzonderlijke Bézier-curves (zie tekening), eventueel met één of twee interactieve controlepunten.

Voor het maken van de interactieve Flash-Illustrator animatie zijn alleen de gegevens van de Bézier-curves van belang. Dit zijn de begin- en eindpositie, de posities van de eventuele controlepunten en de lijndikte.

Lijndikte

De lijndikte van een Bézier-curve wordt gevormd door één enkel getal, gevolgd door de letter 'w'.

0.50000 w

Deze regel definieert dat de lijndikte 0.5 bedraagt.

0 J 0 j 0.5 w 4 M []0 d

Binnen deze regel komt ook de combinatie getal - 'w' voor, naast een aantal andere combinaties van getallen en letters. Maar deze regel is niet relevant voor onze animatie. Alleen een getal gevolgd door de letter 'w' op een aparte regel is relevant voor het bepalen van de lijndikte.

Posities en controlepunten Bézier-curve

Een Bézier-curve wordt beschreven door een aantal getallen, gevolgd door een beperkt aantal letters (afhankelijk van de aanwezigheid van controlepunten).

Een Bézier-curve start met twee getallen, gevolgd door de letter 'm' (van MoveTo).

41.106 41.422 m

Binnen Adobe Illustrator kan een begin- of eindpositie aan meerdere Bézier-curves gekoppeld zijn: de eindpositie van een Bézier-curve kan de beginpositie van een aangrenzende Bézier-curve zijn. Bij het verplaatsen van deze positie binnen Illustrator verander je in één keer de posities van beide Bézier-curves. Wanneer begin- en eindpositie van elke Bézier-curve afzonderlijk opgeslagen zouden worden, zou je twee keer dezelfde positie moeten verplaatsen, wat het gebruiksgemak binnen Illustrator niet ten goede zou komen.

Een aantal cijfer- en lettercombinaties is van belang, te weten een aantal getallen gevolgd door de letters 'c', 'C', 'l', 'L', 'm', 'M', 'v', 'V', 'y' en 'Y'. Het aantal getallen dat voorafgaat aan deze letters is afhankelijk van de specifieke letter. Er worden zowel hoofdletters als onderkastletters in het Adobe Illustrator-bestand gebruikt. In deze handleiding gebruik ik alleen onderkastletters.

Hieronder staat een overzicht van de cijfer- en lettercombinaties die relevant zijn voor de Bézier-curves.

positie_0 (x,y positie) m
positie_0 (x,y positie) l
positie_0 (x,y positie) positie_1 (x,y positie) positie_2 (x,y positie) c
positie_0 (x,y positie) positie_1 (x,y positie) y
positie_0 (x,y positie) positie_1 (x,y positie) v

m = start positie
l = eind positie van rechte lijn
c = cubic Bézier-curve (twee controle punten)
y of v = quadratic Bézier-curve (één controle punt)

Onderstaande afbeelding laat zien hoe je de cryptische Adobe Illustrator-notatie kunt ontcijferen:


positie code uit het Illustrator-bestand
A -23.89 -40.64 m
B -23.89 -19.30 l
0 1 C -23.93 13.11 36.51 -55.48 45.82 -28.14 c
2 D 57.07 4.86 5.57 27.36 y
3 E -47.43 53.36 -47.43 32.61 v

De volgende vier afzonderlijke Bézier-curves zijn uit het Adobe Illustrator-bestand gehaald:

De posities van de Bézier-curves die we uit het Illustrator-bestand hebben gehaald worden in een zogenaamde array in het actionscript geplaatst. Een array is een lijst met variabelen, in dit geval getallen. De gegevens van de Bézier-curves worden als volgt in de lijst verwerkt: lijndikte, beginpositie (x en y positie), eindpositie (x en y positie), eventueel controlepunt van de beginpositie (x en y positie) en het eventuele controlepunt van de eindpositie (x en y positie).

Wanneer er geen controlepunten aanwezig zijn, worden in de array de waarden -999.00,-999.00 gebruikt, omdat de variabelen in de array getallen moeten zijn. De waarde -999.00 is gekozen omdat deze waarde buiten het bereik van de overige posities ligt. In de actionscriptcode van de Flash-animatie wordt gecontroleerd op de waarde -999.00, om te zien of er wel of geen controlepunten getekend moeten worden.

De array van het voorbeeld ziet er als volgt uit:

 var bezier_data:Array=new Array(
  new Array(1.00, -23.89,-40.64, -23.89,-19.30, -999.00,-999.00, -999.00,-999.00),
  new Array(1.00, -23.89,-19.30,  45.82,-28.14,  -23.93,  13.11,   36.50, -55.48),
  new Array(1.00,  45.82,-28.14,   5.57, 27.36,   57.07,   4.86, -999.00,-999.00),
  new Array(1.00,   5.57, 27.36, -47.43, 32.61, -999.00,-999.00,  -47.43,  53.36)
 );

Adobe Illustrator heeft een ander coördinatensysteem dan Macromedia Flash (zie afbeelding). Om de Illustrator-afbeelding op dezelfde wijze weer te geven in Flash is het noodzakelijk om de y positie aan te passen. Het teken van de y positie moet omgekeerd worden: positief wordt negatief en negatief wordt positief. Het omkeren van het teken van de y positie gebeurt in de Flash-animatie met behulp van actionscript.

Voor de interactieve Flash-Illustrator animatie gebruik ik de volgende Illustrator-afbeelding:

Deze Illustrator-afbeelding is gemaakt naar aanleiding van het schilderij 'de geboorte van Venus' van de Italiaanse schilder Sandro Botticelli (1445-1510). De voorgaande Adobe Illustrator versies lieten een fragment – het hoofd – van dit schilderij zien als opstartscherm.

Om het wat makkelijker te maken heb ik een Java-applet gemaakt dat alle gewenste gegevens uit je Illustrator bestand (versie 3.2) haalt.

Nu zijn alle relevante gegevens van de Bézier-curves uit het Illustrator-bestand gehaald, en kunnen we beginnen met de Flash-animatie!

Bézier-curves en Flash

Illustrator maakt gebruik van zowel quadratic Bézier-curves als cubic bezier curves. Macromedia Flash ondersteunt echter alleen quadratic Bézier-curves, die met behulp van het actionscriptcommando 'curveTo' getekend worden.

Tijdens de voorbereiding van de interactieve Flash-Illustrator animatie heb ik het al even gehad over de vraag of een cubic bezier curve te tekenen is binnen Macromedia Flash. Het is raadzaam om (voor je daadwerkelijk aan een project begint) te weten wat je precies wilt maken en vervolgens uit te zoeken of het technisch haalbaar is. Wanneer iets niet direct met standaardoplossingen mogelijk is, volgt de vraag of je het gewenste resultaat via een omweg kunt realiseren.

Omdat Flash geen standaard actionscriptcommando's heeft om een cubic Bézier-curve te tekenen, moest ik uitzoeken of het via een omweg wel mogelijk was. Gelukkig was Timothée Groleau hiermee al aan het werk geweest en had hij er bovendien een erg goede handleiding over geschreven. Kort samengevat kun je een cubic Bézier-curve bijna perfect namaken door vier quadratic Bézier-curves binnen Macromedia Flash te combineren (zie afbeelding).

Afbeelding één toont de originele cubic Bézier-curve uit het Illustrator-bestand, afbeelding twaalf toont dezelfde cubic Bézier-curve in Flash. De cubic Bézier-curve in Flash toont de vier afzonderlijke quadratic Bézier-curves getekent met het actionscriptcommando 'curveTo'. De vier quadratic Bézier-curves worden gevormd door posities 0,1,2, 2,3,4, 4,5,6 en 6,7,8 (afbeelding elf).

Opbouw van de Flash-animatie

De Flash-animatie is schematisch als volgt opgebouwd:

Er zijn twee aparte movieclips gebruikt om een verdeling te maken tussen de ‘voorgrond’ (interface) en de ‘achtergrond’ (canvas) in de movieclip ‘animation’ in _level1. De ‘voorgrond’ – de blauwe elementen – bestaat uit de begin- en eindpositie van de Bézier-curve, de eventuele controlepunten en een lijn tussen de begin- of eindpositie en het bijbehorende controlepunt. Deze lijn zorgt ervoor dat duidelijk is welk controlepunt bij welke begin- of eindpositie hoort. De ‘achtergrond’ bestaat uit de Illustrator-afbeelding.

De movieclip ‘animation’ bevat het grootste deel van de actionscript code. Er is gebruik gemaakt van een extern actionscriptbestand. De volgende actionscriptcode verwijst naar dit externe bestand.

#include "script_00.as"

Dit actionscriptbestand bestaat uit een aantal functies. Functies zijn apart stukjes code die een bepaalde taak uitvoeren.

Voordat de interactieve Flash-Illustrator animatie beeld laat zien, wordt de data in de array – afkomstig van het Illustrator-bestand – aangepast aan het formaat van de Flash-animatie. De functie ‘initialize’ wordt aangeroepen en schaalt de posities naar het maximaal mogelijke beeldformaat. Naast het schalen van de posities worden de posities ook horizontaal en verticaal getransleert of ge'offset. Een offset is een positief of negatief getal die je bij een ander getal – in dit geval een positie – optelt. De horizontale en verticale offset zorgen er voor dat de Illustrator afbeelding exact in het centrum van de Macromedia Flash animatie zichtbaar is.

De aangepaste posities worden in de array teruggeplaatst, waardoor de originele posities overgeschreven worden.

Binnen de functie ‘initialize’ wordt gecontroleerd op het getal -999.0. Het getal worden gebruikt om aan te geven dat er geen controlepunt aanwezig is. Deze waarde wordt niet geschaald, omdat deze waarde slechts dient als controlewaarde.

De functie 'initialize' ziet er als volgt uit:


  /*************************************************************************/
  /*                                                                       */
  /* copyright 2004 Arjan Westerdiep / www.drububu.com                     */
  /*                                                                       */
  /*************************************************************************/

  initialize = function()
  {var a,b,min_x,min_y,max_x,max_y,scale,offset_x,offset_y;Number

   /************************************************************************/
   /* add link                                                             */
   /************************************************************************/

   _parent.info ="<a href='http://www.drububu.com' target='_blank'>";
   _parent.info+="<font color='#808080'>COPYRIGHT ARJAN WESTERDIEP / ";
   _parent.info+="WWW.DRUBUBU.COM</font></a>";

   /************************************************************************/
   /* initialize min./max.                                                 */
   /************************************************************************/

   min_x= bezier_data[0][1];
   max_x= min_x;
   min_y=-bezier_data[0][2];
   max_y= min_y;

   /************************************************************************/
   /* check positions                                                      */
   /************************************************************************/

   for(a=bezier_data.length; --a>=0;){

    bezier_data[a][2]=-bezier_data[a][2]; 
    bezier_data[a][4]=-bezier_data[a][4];
    bezier_data[a][6]=-bezier_data[a][6];
    bezier_data[a][8]=-bezier_data[a][8];

    bezier_data[a][1]>bezier_data[a][3] ? b=1 : b=3;

    if(bezier_data[a][  b]>max_x){ max_x=bezier_data[a][  b];}
    if(bezier_data[a][4-b]<min_x){ min_x=bezier_data[a][4-b];}

    bezier_data[a][2]>bezier_data[a][4] ? b=2 : b=4;

    if(bezier_data[a][  b]>max_y){ max_y=bezier_data[a][  b];}
    if(bezier_data[a][6-b]<min_y){ min_y=bezier_data[a][6-b];}
   }

   /************************************************************************/
   /* initialize scale and offsets                                         */
   /************************************************************************/

   a=(WIDTH -(BORDER<<1))/(max_x-min_x);
   b=(HEIGHT-(BORDER<<1))/(max_y-min_y);

   a<b ? scale=a : scale=b;

   offset_x=(WIDTH >>1)-((scale*(max_x-min_x))/2.0);
   offset_y=(HEIGHT>>1)-((scale*(max_y-min_y))/2.0);

   /************************************************************************/
   /* scale and repositioning positions                                    */
   /************************************************************************/

   for(a=bezier_data.length; --a>=0;){                  

    bezier_data[a][0]*=scale;                         

    bezier_data[a][1]=offset_x+((bezier_data[a][1]-min_x)*scale);
    bezier_data[a][2]=offset_y+((bezier_data[a][2]-min_y)*scale);

    bezier_data[a][3]=offset_x+((bezier_data[a][3]-min_x)*scale);
    bezier_data[a][4]=offset_y+((bezier_data[a][4]-min_y)*scale);

    if(bezier_data[a][5]!=-999.0){
     bezier_data[a][5]=offset_x+((bezier_data[a][5]-min_x)*scale);
     bezier_data[a][6]=offset_y+((bezier_data[a][6]-min_y)*scale);
    }

    if(bezier_data[a][7]!=-999.0){
     bezier_data[a][7]=offset_x+((bezier_data[a][7]-min_x)*scale);
     bezier_data[a][8]=offset_y+((bezier_data[a][8]-min_y)*scale);
    }
   }                                                

   /************************************************************************/
   /* start drawing bezier curves                                          */
   /************************************************************************/

   mListener.onMouseMove=undefined;
   counter=0;

   onEnterFrame = function()
   {
    draw_illustration();
   }
  }


De laatste regels actionscriptcode roepen de functie ‘draw_illustration’ aan.

onEnterFrame = function() { draw_illustration(); }

De functie ‘draw_illustration’ tekent per frame een Bézier-curve, net zolang totdat alle Bézier-curves getekend zijn. De keuze om per frame een Bézier-curve te tekenen is gebaseerd op de vrij lage rekenkracht van Flash. Wanneer alle Bézier-curves in een keer getekend zouden worden, levert dat een te grote aanslag op de processor van de bezoeker op, zeker wanneer de Illustrator-afbeelding uit veel Bézier-curves bestaat.

Tijdens het tekenen van de Bézier-curves worden met behulp van actionscript een aantal movieclips gedupliceerd, waardoor nieuwe movieclips ontstaan.

Het dupliceren van de movieclips gebeurt met de volgende regels actionscript:

if(counter!=0){
  this.interface_0.duplicateMovieClip("interface_"+counter,3+counter);
  this.canvas.bezier_0.duplicateMovieClip("bezier_"+counter,counter);
 }

De variabele ‘counter’ telt het aantal getekende Bézier-curves. De eerste Bézier-curve die getekend wordt maakt gebruik van de movieclips die aanwezig zijn, de Bézier-curves die volgen maken gebruik van een gedupliceerde versie van de reeds aanwezige movieclips.

Per Bézier-curve zijn er twee movieclips, één voor het tekenen van de interface (‘interface_0’, ‘interface_1’, ‘interface_2’ etc.) en één voor het tekenen van de Bézier-curves (‘bezier_0’, ‘bezier_1’ ,‘bezier_2’ etc.). De movieclips ‘interface_xx’ worden gedupliceerd binnen de movieclip ‘animation’, de movieclips ‘bezier_xx’ worden gedupliceerd in de movieclip ‘canvas’. Doordat de movieclips in de movieclip ‘canvas’ gedupliceerd worden, bevindt de gehele Illustrator-afbeelding zich in de movieclip ‘animation’ (een niveau hoger) in de onderste layer. Alle interactieve – blauwe –– beeldelementen liggen boven de Illustrator-afbeelding in de movieclip ‘animation’.

De functie 'draw_illustration' ziet er als volgt uit:


  /*************************************************************************/
  /*                                                                       */
  /* copyright 2004 Arjan Westerdiep / www.drububu.com                     */
  /*                                                                       */
  /*************************************************************************/

  draw_illustration = function()
  {
   if(counter!=0){
    this.interface_0.duplicateMovieClip("interface_"+counter,3+counter);
    this.canvas.bezier_0.duplicateMovieClip("bezier_"+counter,counter);
   }

   /************************************************************************/
   /* initialize positions and eventually remove movieclips                */
   /************************************************************************/

   a=this["interface_"+counter];

   a.bezier.clear();

   /************************************************************************/
   /* start position                                                       */
   /************************************************************************/

   a.anchor_0._x=bezier_data[counter][1];
   a.anchor_0._y=bezier_data[counter][2];
   a.line_0.clear();
   a.handle_0._visible=bezier_data[counter][5]==-999.0 ? false : true;

   /************************************************************************/
   /* end position                                                         */
   /************************************************************************/

   a.anchor_1._x=bezier_data[counter][3];
   a.anchor_1._y=bezier_data[counter][4];
   a.line_1.clear();
   a.handle_1._visible=bezier_data[counter][7]==-999.0 ? false : true;

   /************************************************************************/
   /* draw line                                                            */
   /************************************************************************/

   if(bezier_data[counter][5]==-999.0 && bezier_data[counter][7]==-999.0){
    b=this.canvas["bezier_"+counter];
    b.clear();
    b.lineStyle(bezier_data[counter][0],0x000000);
    b.moveTo(bezier_data[counter][1],bezier_data[counter][2]); 
    b.lineTo(bezier_data[counter][3],bezier_data[counter][4]); 
   }

   /************************************************************************/
   /* draw bezier curve                                                    */
   /************************************************************************/

   else {
    draw_bezier_curve(counter);
   }

   counter++;

   if(counter==bezier_data.length){
    onEnterFrame=undefined;
   }
  }
  

Tijdens het opbouwen van de Illustrator-afbeelding worden de Bézier-curves getekend met behulp van de functie ‘draw_bezier_curve’.

Binnen de functie wordt gecontroleerd of de Bézier-curve een rechte lijn is. Zoals je vast nog wel weet is dit het geval wanneer de Bézier-curve geen controlepunten heeft. Het tekenen van een rechte lijn vindt binnen de functie plaats, omdat een rechte lijn niet interactief is: alleen Bézier-curves (één of twee controlepunten) zijn interactief.

Het tekenen van een Bézier-curve is in een aparte functie ondergebracht, omdat er op twee plaatsen in de actionscriptcode gebruik van wordt gemaakt: tijdens het opbouwen van de interactieve Flash-Illustrator animatie en wanneer de gebruiker interactief de controlepunten wijzigt. Door specifieke taken die meerdere keren voorkomen in een aparte functie te plaatsen voorkom je dat je telkens dezelfde actionscriptcodes typt.

Wanneer alle Bézier-curves getekend zijn stopt de animatie.

De functie ‘draw_bezier_curve’ ziet er als volgt uit:


  /*************************************************************************/
  /*                                                                       */
  /* copyright 2004 Arjan Westerdiep / www.drububu.com                     */
  /*                                                                       */
  /*************************************************************************/

  draw_bezier_curve = function(i:Number)
  {var a;

   /************************************************************************/
   /* draw line between anchor point and control point if present.         */
   /************************************************************************/

   if(bezier_data[i][5]!=-999.0 &&
      (this["interface_"+i].handle_0._x!=bezier_data[i][5]||
       this["interface_"+i].handle_0._y!=bezier_data[i][6])){
    draw_line(i,0);
   }

   if(bezier_data[i][7]!=-999.0 &&
      (this["interface_"+i].handle_1._x!=bezier_data[i][7]||
       this["interface_"+i].handle_1._y!=bezier_data[i][8])){
    draw_line(i,1);
   }

   /************************************************************************/
   /* init.                                                                */
   /************************************************************************/

   a=this.canvas["bezier_"+i];
   a.clear();
   a.lineStyle(bezier_data[i][0],0x000000);

   /************************************************************************/
   /*                                                                      */
   /* draw quadratic bezier curve                                          */
   /*                                                                      */
   /************************************************************************/

   if((bezier_data[i][5]!=-999.0 && bezier_data[i][7]==-999.0)||
      (bezier_data[i][5]==-999.0 && bezier_data[i][7]!=-999.0)){

    a.moveTo( bezier_data[i][1],bezier_data[i][2]); 

    a.curveTo(bezier_data[i][bezier_data[i][5]==-999.0 ? 7 : 5],
              bezier_data[i][bezier_data[i][5]==-999.0 ? 8 : 6],
              bezier_data[i][3],bezier_data[i][4]); 
   }

   /************************************************************************/
   /*                                                                      */
   /* draw cubic bezier curve                                              */
   /*                                                                      */
   /************************************************************************/

   else  {

    var pos:Array=new Array(new Array(2),
                            new Array(2),
                            new Array(2),
                            new Array(2),
                            new Array(2),
                            new Array(2),
                            new Array(2),
                            new Array(2),
                            new Array(2));

    /***********************************************************************/
    /* initialize positions cubic bezier_curve                             */
    /***********************************************************************/
 
    pos[0][0] =bezier_data[i][1];
    pos[0][1] =bezier_data[i][2];
  
    pos[8][0] =bezier_data[i][3];
    pos[8][1] =bezier_data[i][4];
 
    pos[1][0] =pos[0][0]        +0.50*(bezier_data[i][5]-pos[0][0]        );
    pos[1][1] =pos[0][1]        +0.50*(bezier_data[i][6]-pos[0][1]        );

    pos[4][0] =bezier_data[i][5]+0.50*(bezier_data[i][7]-bezier_data[i][5]);
    pos[4][1] =bezier_data[i][6]+0.50*(bezier_data[i][8]-bezier_data[i][6]);

    pos[7][0] =pos[8][0]        +0.50*(bezier_data[i][7]-pos[8][0]        );
    pos[7][1] =pos[8][1]        +0.50*(bezier_data[i][8]-pos[8][1]        );
    
    pos[3][0] =pos[4][0]        +0.50*(pos[1][0]        -pos[4][0]        );
    pos[3][1] =pos[4][1]        +0.50*(pos[1][1]        -pos[4][1]        );

    pos[5][0] =pos[4][0]        +0.50*(pos[7][0]        -pos[4][0]        );
    pos[5][1] =pos[4][1]        +0.50*(pos[7][1]        -pos[4][1]        );

    pos[4][0] =pos[3][0]        +0.50*(pos[5][0]        -pos[3][0]        );
    pos[4][1] =pos[3][1]        +0.50*(pos[5][1]        -pos[3][1]        );

    pos[3][0]+=                  0.25*(pos[4][0]        -pos[3][0]        );
    pos[3][1]+=                  0.25*(pos[4][1]        -pos[3][1]        );

    pos[5][0]+=                  0.25*(pos[4][0]        -pos[5][0]        );
    pos[5][1]+=                  0.25*(pos[4][1]        -pos[5][1]        );

    pos[1][0]+=                  0.25*(pos[0][0]        -pos[1][0]        );
    pos[1][1]+=                  0.25*(pos[0][1]        -pos[1][1]        );

    pos[7][0]+=                  0.25*(pos[8][0]        -pos[7][0]        );
    pos[7][1]+=                  0.25*(pos[8][1]        -pos[7][1]        );

    pos[2][0] =pos[1][0]        +0.50*(pos[3][0]        -pos[1][0]        );
    pos[2][1] =pos[1][1]        +0.50*(pos[3][1]        -pos[1][1]        );

    pos[6][0] =pos[7][0]        +0.50*(pos[5][0]        -pos[7][0]        );
    pos[6][1] =pos[7][1]        +0.50*(pos[5][1]        -pos[7][1]        );

    a.moveTo(pos[0][0],pos[0][1]); 
    a.curveTo(pos[1][0],pos[1][1],pos[2][0],pos[2][1]); 
    a.curveTo(pos[3][0],pos[3][1],pos[4][0],pos[4][1]); 
    a.curveTo(pos[5][0],pos[5][1],pos[6][0],pos[6][1]); 
    a.curveTo(pos[7][0],pos[7][1],pos[8][0],pos[8][1]); 
   }
  }


De functie tekent naast de Bézier-curve ook de controlepunten en de lijn tussen controlepunt en begin- of eindpositie. De functie ‘draw_line’ wordt aangeroepen voor het tekenen van deze lijn.

De functie ‘draw_line’ ziet er als volgt uit:


  /*************************************************************************/
  /*                                                                       */
  /* copyright 2004 Arjan Westerdiep / www.drububu.com                     */
  /*                                                                       */
  /*************************************************************************/

  draw_line = function(i:Number,j:Number)
  {var a:Number;

   a=1+(j<<1);

   b=this["interface_"+i]["line_"+j];
   b.clear();
   b.lineStyle(2,0x4F80FF);
   b.moveTo(bezier_data[i][a  ],bezier_data[i][a+1]);
   b.lineTo(bezier_data[i][a+4],bezier_data[i][a+5]);

   this["interface_"+i]["handle_"+j]._x=bezier_data[i][a+4];
   this["interface_"+i]["handle_"+j]._y=bezier_data[i][a+5];
  }
  

Interactiviteit

De Illustrator-afbeelding is nu zichtbaar in de interactieve Flash-Illustrator animatie. De laatste fase is het toevoegen van interactiviteit. De volgende afbeelding laat zien welke movieclips (grijze achtergrond) gebruikt worden voor de interactiviteit.

De movieclip ‘interface’ bestaat uit een aantal layers met daarin o.a. de movieclips ‘handle 0’ en ‘handle 1’. Beide movieclips zijn een kopie van de movieclip ‘control point’. De movieclip ‘control point’ bestaat uit een graphic en een button. De button wordt gebruikt om te detecteren of de gebruiker op een controlepunt klikt.

Het detecteren van klikken gebeurt met actionscript in de movieclip ‘interface’ een niveau hoger. De button in de movielclip ‘control point’ krijgt de naam ‘button’ in het property window van Macromedia Flash (zie afbeelding).

De movieclips in de layers ‘handle 0’ en ‘handle 1’ van de movieclip ‘interface’ krijgen de namen ‘handle_0’ en ‘handle_1’ (zie afbeelding).

Met behulp van de actionscript in de movieclip ‘interface’ kunnen we nu controleren of de gebruiker op één van beide controlepunten klikt. De actionscriptcode ziet er als volgt uit:

 var index:Number=int(_name.substr(10,_name.length-10));
 
  handle_0.button.onPress = function()
  {
   _parent.selection_handle(index,0);
  }
  
  handle_1.button.onPress =function()
  {
   _parent.selection_handle(index,1);
  }
 
  stop();

De variabele ‘index’ is een getal. Het getal komt overeen met het nummer aan het eind van de naam van de specifieke movieclip. Tijdens het opbouwen van de interactieve animatie zijn per Bézier-curve movieclips gedupliceerd. Elke gedupliceerde movieclip heeft een unieke naam gekregen. De gedupliceerde movieclips heten interface_1, interface_2, interface_3 enz. Het getal aan het einde van de movieclipnaam refereert naar de Bézier-curve uit de array in de movieclip ‘animation’.

Het actionscript dat volgt controleert of er op één van beide controle punten geklikt wordt. Zodra de gebruiker op een controlepunt klikt wordt de functie ‘selection_handle’ aangeroepen. De aanroep geeft de index van de betreffende movieclip mee, plus de index van het controlepunt waarop geklikt is. Binnen de actionscript in de movieclip ‘animation’ is nu bekend welke Bézier-curve geselecteerd is. Daarnaast is bekend of het controlepunt aan de begin- of eindpositie van de Bézier-curve gekoppeld is.

Zodra de gebruiker het geselecteerde controle punt gaat slepen, wordt de nieuwe muispositie in de array opgeslagen en volgt de aanroep van de functie ‘draw_bezier_curve’. De Bézier-curve van het geselecteerde controlepunt wordt aangepast aan de nieuwe positie van het controlepunt.

De functie ‘selection_handle’ ziet er als volgt uit:


  /*************************************************************************/
  /*                                                                       */
  /* copyright 2004 Arjan Westerdiep / www.drububu.com                     */
  /*                                                                       */
  /*************************************************************************/

  selection_handle = function(index:Number,control_point_index:Number)
  {
   mListener.onMouseMove = function()
   {var i:Number;

    i=5+(control_point_index*2);
    bezier_data[index][i  ]=_xmouse;
    bezier_data[index][i+1]=_ymouse;
    draw_bezier_curve(index);
   }
  }
  

De interactieve Flash-Illustrator animatie is compleet; klik op de afbeelding om de animatie te bekijken.

Conclusie

Het omzetten van een Adobe Illustrator-afbeelding naar Macromedia Flash met behulp van actionscript is ingewikkeld, maar minder ingewikkeld dan je zou verwachten. Het vereist enige kennis van zowel de opbouw van een Adobe Illustrator-bestand als kennis van actionscript.

In veel gevallen is het niet nodig om volledig te weten hoe bijvoorbeeld een Adobe Illustrator bestand in elkaar zit. Voor deze interactieve Flash-Illustrator animatie volstaat het te weten hoe de informatie van de Bézier-curves en de lijndikte uit te lezen zijn.

De kennis om Bézier-curves uit een Illustrator-bestand te isoleren kun je ook gebruiken om direct in Illustrator-bestanden beeld te genereren. Bij de Illustrator-afbeelding van de Venus zijn de schelp en het hoofd op deze wijze gegenereerd.
In veel gevallen leidt inzicht in techniek tot nieuwe – vaak onvoorziene – mogelijkheden. Een ander voordeel van inzicht in techniek is dat je beter keuzes kunt maken wat wel te doen en wat vooral niet te doen.

Door vooraf te inventariseren of iets mogelijk is en te onderzoeken of eventuele technische beperkingen te omzeilen zijn is het mogelijk efficiënt tot concrete eindresultaten te komen.

Download de Flash bestanden (zip - 41kB)

Haal de gewenste gegevens uit je Illustrator bestand met behulp van het Java-applet.

Meer weten?

Wil je meer weten hoe een willekeurig bestandsformaat precies opgebouwd is, kijk dan eens op the programmer's file format collection.

Mochten er nog vragen en/of opmerkingen zijn naar aanleiding van deze handleiding, dan kun je contact opnemen met arjan@drububu.com.

Auteur

Arjan Westerdiep

is ook voor jouw website te huur als grafisch ontwerper, illustrator of het programmeren van beeld.

Hij is woordblind, vindt iets mooi of lelijk, houdt niet van concessies doen en is de maker van www.drububu.com.

Publicatiedatum: 23 november 2004

Let op

Naar Voren is op 18 juli 2010 gestopt met publiceren. De artikelen staan als een soort archief online. Het kan dus zijn dat de informatie verouderd is en dat er inmiddels veel betere of makkelijkere manieren zijn om je doel te bereiken.

Copyright © 2002-heden » NAAR VOREN en de auteurs