TAChart Tutorial: ColorMapSeries, Zooming/fi: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: TAChart Tutorial: ColorMapSeries, Zooming/fi
| Old | New | Line | |
|---|---|---|---|
| 1 | + | ## Johdanto | |
| 2 | + | ||
| 3 | + |  | |
| 4 | + | ||
| 5 | + | ["Mandelbrotin joukko"](http://fi.wikipedia.org/wiki/Mandelbrotin_joukko), nimetty Benoît Mandelbrotin mukaan, on niin sanottu "fraktaali" -- kaksiulotteinen muoto, joka on tunnettu siitä että se on itsesimilaarinen eri mittakaavoissa. Fraktaalin suurentaminen paljastaa pienimuotoisia yksityiskohtia joka ovat samanlaisia kuin laajamittaiset ominaisuudet. Tässä opetusohjelmassa käytetään [[TAChart]]-komponenttia piirtämään Mandelbrot joukon **värikarttakuvaajan** avulla ja käytetään erilaisia zoomausta tekniikoilla, kuten zoomausta vetämällä tai asettamalla **extent** historia. Kuten tavallista, tämä vaatii perustiedot työskennellä TAChart-komponentin kanssa jonka perustiedot saadaan kun käydään läpi [[TAChart Tutorial: Getting started|"Aloitus" opetusohjelma]] . Ja tietenkin, pitää olla perustiedot Lazarus IDE:stä ja Object Pascal kielestä. | |
| 6 | + | ||
| 7 | + | ## Värikarttakuvaajan (TColormapSeries) käyttö | |
| 8 | + | ||
| 9 | + | Mikä on [[TAChart documentation|TColorMapSeries]]? Normaalisti työskennellään kuvaajien kanssa jotka sisältävät kaksiulotteista dataa - yhdellä akselilla on *X*- koordinaatit ja toisella *y*:n arvot, jotka on määritetty *x*:n arvojen suhteen. Värikarttakuvaaja (`TColorMapSeries`) on tästä poikkeus: se näyttää kolmiulotteista dataa : meillä on piste *xy* ja kolmas arvo, sen korkeus joka liitetään *xy*-tasoon. Usein 3D pisteitä, katsotaan kuin vuoria maiseman yläpuolella, pohjan tasossa. Valitettavasti TAChart ei voi piirtää 3D-näkymiä. Mutta on olemassa vaihtoehto: korkeus, alustan tason yläpuolella voi voidaan kuvata värillä, tämä tarkoittaa että kaavio täyttää xy-tason väreillä, jotka vastaavat kolmannen tason koordinaatteja. | |
| 10 | + | ||
| 11 | + | Värikarttakuvaaja (`TColorMapSeries`) on funktionaalinen kuvaaja, mikä tarkoittaa sitä että se ei voi piirtää mielivaltaista dataa, vaan dataa, jotka voidaan laskea funktiona. Tätä tarkoitusta varten kuvaajalla on tapahtuma `OnCalculate` jota kutsutaan jokaisen (*x*, *y*) pisteelle siirtämään funktion arvo. Tässä mielessä `TColorMapSeries` on samanlainen kuin funktiokuvaaja (`TFuncSeries`) jonka käyttöä opetettiin [[TAChart Tutorial: Function Series/fi|toisessa opetusohjelmassa]] . | |
| 12 | + | ||
| 13 | + | Toinen "perusraaka-aine" on `ColorSource` joka kuvaa funktion arvot värin. Tähän tarkoitukseen on kätevä käyttää `TListChartSource`-komponentti. Yleisesti, se tallentaa *x* ja *y*:n arvojen kanssa väriarvon ja kuvaavan etiketin `TChartDataItem`, mutta värikarttakuvaajaa varten tarvitaan vain *x*- ja väri merkintöjä. | |
| 14 | + | ||
| 15 | + | Valmis aloittamaan? | |
| 16 | + | ||
| 17 | + | Luo uusi projekti ja lisää client-aligned `TChart`-komponentti. Älä tee ikkunasta liian suurta, koska tämän opetusohjelman projekti vaatii paljon laskentaa ja suuri määrä pikseleitä heikentää suorituskykyä ... Kaksoisklikkaa kaaviota avataksesi "muokkaa kuvaajia" ikkunan ja lisää "Värikarttakuvaaja" kaavioon. Seuraavaksi pudota `TListChartSource` lomakkeelle. Tämä on värin lähde Värikarttakuvaajalle (ColorMapSeries). Joten, nimeä se "`ColorSource`" ja liitä se vastaavaan omaisuuteen kuvaajassa. | |
| 18 | + | ||
| 19 | + |  | |
| 20 | + | ||
| 21 | + | ## Värikarttaan tutustuminen | |
| 22 | + | ||
| 23 | + | Jotta saadaan joitakin perehtyneisyyttä tästä uudesta ympäristöstä, voidaan aloittaa tekemällä yksinkertainen esimerkki: käytetään värikarttakuvaajaa piirtämään liukuvärjäys *x*-akselille. | |
| 24 | + | ||
| 25 | + | Aluksi kirjoitetaan ColorMapSeries:n tapahtuman käsittelijä `OnCalculate`. Tämä on helppoa, koska halutaan vain yksinkertainen lineaarinen gradientti eli liukuvärjäys: | |
| 26 | + | ||
| 27 | + | ``` pascal | |
| 28 | + | procedure TForm1.Chart1ColorMapSeries1Calculate(const AX, AY: Double; | |
| 29 | + | out AZ: Double); | |
| 30 | + | var | |
| 31 | + | ext: TDoubleRect; // unit TAChartUtils.pas | |
| 32 | + | begin | |
| 33 | + | ext := Chart1.GetFullExtent; | |
| 34 | + | AZ := (AX - ext.a.x) /(ext.b.x - ext.a.x); | |
| 35 | + | end; | |
| 36 | + | ``` | |
| 37 | + | ||
| 38 | + | Jotta ollaan riippumattomia kaavion koosta normalisoidaan *x*-koordinaatti alueelle *x* datat ( [[TAChart documentation|graph units]]). *X* alue voidaan laskea kaavion [[TAChart documentation|FullExtent]] - tämä on suorakulmio kaksinkertaisen tarkkuuden arvot on määritelty kulmassa oleva kaavion piirtämällä suorakulmio ennen kuin zoomausta tai panorointia tehdään. Normalisoituminen kuten yllä varmistaa, että AZ on 0 vasemmalla ja 1 oikealla *x*-akselin lopussa. | |
| 39 | + | ||
| 40 | + | Lopuksi täytyy täyttää ColorSource asetus liukuvärjäyksellä. Tämä on erittäin helppoa, koska ColorMapSeries tekee kaikki interpoloinnit jos sen omaisuus `Interpolate` asetetaan arvoon `true`. | |
| 41 | + | ||
| 42 | + | Likuvärjäyksen määrittely aloitetaan arvosta 0,0 ja se määritetään siniseksi väriksi. Lopussa liukuvärjäys vastaa arvoa 1,0 ja sen pitäisi näkyä keltaisena. Nämä tehtävät tehdään aliohjelmassa `PopulateColorSource` jota kutsumme `OnCreate` lomakkeen tapahtumassa; käytämme erillisessä aliohjelmaa, koska joitakin muutoksia tehdään koko tämän opetusohjelma ajan ja haluataan pitää asiat erillään. | |
| 43 | + | ||
| 44 | + | ``` pascal | |
| 45 | + | procedure TForm1.FormCreate(Sender: TObject); | |
| 46 | + | begin | |
| 47 | + | PopulateColorSource; | |
| 48 | + | end; | |
| 49 | + | ||
| 50 | + | procedure TForm1.PopulateColorSource; | |
| 51 | + | const | |
| 52 | + | DUMMY = 0.0; | |
| 53 | + | begin | |
| 54 | + | with ColorSource do begin | |
| 55 | + | Add(0.0, DUMMY, '', clBlue); // 0.0 --> sininen | |
| 56 | + | Add(1.0, DUMMY, '', clYellow); // 1.0 --> keltainen | |
| 57 | + | end; | |
| 58 | + | end; | |
| 59 | + | ``` | |
| 60 | + | ||
| 61 | + | Johtuen `TListChartSource.Add` syntaksista täytyy antaa arvoja *y*-koordinaatille ja marks tekstille, käytetään siihen vakiota `DUMMY` ja tyhjää merkkijonoa koska niitä tarvita. | |
| 62 | + | ||
| 63 | + | Ajetaan ohjelma. Jos ei nähdä liukuvärjäystä niin ehkä on unohtunut aktivoida ColorMapSource:n `Interpolate` asetus. Jos hyvin tarkkaan katsotaan niin nähdään joitakin värisävyjen kapeita ryhmittelyjä erityisesti keskustan siirtymäalueella. Tämä johtuu ColorMapSource:n ominaisuuksista `StepX` ja `StepY` jotka ovat edelleen niiden oletusarvossa 4. Tämä tarkoittaa sitä, että xy-tasoa ei tarkisteta pikseli kerrallaan, vaan 4x4 pikselin lohkoissa, tämä nopeuttaa piirtämistä. Asetamalla nämä arvoon 1 päästään eroon ryhmittelystä. Parantunut tarkkuus on myös edullista Mandelbrot joukolle myöhemmin. Kuitenkin se hidastaa ohjelman suoritusta, joka voi olla varsin dramaattista, jos on hidas tietokone ... | |
| 64 | + | ||
| 65 | + |   | |
| 66 | + | ||
| 67 | + | Mennään pidemmälle ja lisätään toinen pivot liukuvärjäykseen. Entä punainen keskellä vastaamaan vaikkapa 0,3? Laitetaan toinen kutsu `Add` osaksi `PopulateColorSource` aliohjelmaa. Koska interpolointi vaatii lajitellun luettelon kannattaa lisätä uusi väri muiden väliin tai sitten pitäisi kutsua `Sort` väriä-arvo-parien lisäämisen jälkeen. Tuloksena on edellä esitetty kolmivärinen liukuvärjäys, käytämme sitä, kun tehdään Mandelbrotin joukkoa. | |
| 68 | + | ||
| 69 | + | ``` pascal | |
| 70 | + | procedure TForm1.PopulateColorSource; | |
| 71 | + | const | |
| 72 | + | DUMMY = 0.0; | |
| 73 | + | begin | |
| 74 | + | with ColorSource do begin | |
| 75 | + | Add(0.0, DUMMY, '', clBlue); // 0.0 --> sininen | |
| 76 | + | Add(0.3, DUMMY, '', clRed); // 0.3 --> punainen | |
| 77 | + | Add(1.0, DUMMY, '', clYellow); // 1.0 --> keltainen | |
| 78 | + | end; | |
| 79 | + | end; | |
| 80 | + | ``` | |
| 81 | + | ||
| 82 | + | ## Mandelbrotin joukko | |
| 83 | + | ||
| 84 | + | Joten mikä on Mandelbrotin joukko? Karkeasti ottaen se on joukko pisteitä *xy*-tasolla jotka noudattavat tiettyä sääntöä, kuten ympyrä, jonka sääntö on, että kaikki ympyrän pisteet(esim joukon) on oltava samalla etäisyydellä origosta. | |
| 85 | + | ||
| 86 | + | Niin Mandelbrotin joukon sääntö on vähän monimutkaisempi. "Kompleksinen" maailma on ymmärrettävä tässä kaksitahoissa mielessä: monimutkainen merkityksessä "monimutkainen", mutta myös monimutkainen matemaattisessa mielessä, että kohtia *xy* käsitellään kuten kompleksilukuja. Jos et ole perehtynyt kompleksilukuihin, älä anna periksi - vältämme täysin laskelmat näillä "oudoilla" numeroilla. | |
| 87 | + | ||
| 88 | + | ### Laskeminen | |
| 89 | + | ||
| 90 | + | Paras tapa ymmärtää Mandelbrotin joukko on tehdä sen rakenne. Käytetään seuraavaa reseptiä jokaiselle 2d pisteelle *xy* tasolla; Näistä lähtöpisteitä on kutsutaan c = (c<sub>x</sub>, c<sub>y</sub>). | |
| 91 | + | ||
| 92 | + | 1. Aloita liittämällä c toiseen pisteeseen z = (z<sub>x</sub>, z<sub>y</sub>) = (c<sub>x</sub>, c<sub>y</sub>). | |
| 93 | + | 2. Laske z:n "neliö" seuraavalla kaavalla: z<sup>2</sup> = (z<sub>x</sub><sup>2</sup> - z<sub>y</sub><sup>2</sup>, 2 * z<sub>x</sub> * z<sub>y</sub>) - tämä kaava voi näyttää hieman oudolta, mutta jos on perehtynyt Kompleksinumeroihin niin huomataan, että se on tapa, miten lasketaan kompleksiluvun neliö. (Jos ei ole perehtynyt niin pidä se annettuna.) | |
| 94 | + | 3. Lisää sitten c:n koordinaatit c kuin `z`<sup>`2`</sup>. Tämän seurauksena vaihe on z<sup>2</sup> + c = (z<sub>x</sub><sup>2</sup> - z<sub>y</sub><sup>2</sup> + c<sub>x</sub>, 2 * z<sub>x</sub> * z<sub>y</sub> + c<sub>y</sub>) | |
| 95 | + | 4. Nyt otetaan tämä tulos ja laitetaan se vaiheen 2 laskuun jälleen uutena z:n arvona | |
| 96 | + | 5. Toista tämä aliohjelma uudestaan ja uudestaan. Tämän seurauksena piste z seuraa jonkinlaisen lentoradan *xy* tasossa. Kuvassa näytämme muutamia esimerkkejä, jotka jäljittää: | |
| 97 | + | -  Punainen ja fuksia käyrät lopulta siirtää pois alkuperä, nämä polut ovat **"rajaton"** (**"unbounded"**). Voidaan osoittaa, että kun polku on ylittänyt kriittisen etäisyyden 2 päässä alkuperää se ei koskaan palaa takaisin ja välttyy äärettömyyteen. Yleensä laskenta laskee toistojen kunnes etäisyys origosta on yli 2. Iteraatioiden lukumäärä on kartoitettu värillä, jota käytetään piirtämän pikselin lähtöpisteestä c. | |
| 98 | + | - Sininen polku, toisaalta, suppenee kohti alkuperää. Vihreä käyrä ei lähentyvät, mutta pysyy paeta säteellä. Molemmat tapaukset ovat nimeltään **"rajoitettujen"** (**"bounded"**). Iteratiivinen laskenta menisi loputtomiin. Siksi se pysäytetään iteraatioiden maksimimäärään. Lähtöpisteet c näille liikeradoille sanotaan kuuluvan Mandelbrotin joukkoon ja piirretään mustalla värillä. | |
| 99 | + | ||
| 100 | + | Vaikka tämä kuvaus voi kuulostaa vähän hankalalta niin vain muutama rivi Pascal koodia tarvitaan laskennassa. Seuraava funktio määrittää, onko piste c Mandelbrotin joukossa vai ei. Se palauttaa tarvittavien iteraatioiden määrän ja pisteen koordinaatit kun viimeinen iteraatio on suoritettu. | |
| 101 | + | ||
| 102 | + | ``` pascal | |
| 103 | + | const | |
| 104 | + | MANDELBROT_NUM_ITERATIONS = 100; | |
| 105 | + | MANDELBROT_ESCAPE_RADIUS = 2.0; | |
| 106 | + | MANDELBROT_LIMIT = sqr(MANDELBROT_ESCAPE_RADIUS); | |
| 107 | + | ||
| 108 | + | function InMandelbrotSet(c:TDoublePoint; out Iterations:Integer; out z: TDoublePoint): Boolean; | |
| 109 | + | var | |
| 110 | + | j: Integer; | |
| 111 | + | begin | |
| 112 | + | Iterations := 0; | |
| 113 | + | z := DoublePoint(0.0, 0.0); // unit TAGeometry.pas | |
| 114 | + | for j:=0 to MANDELBROT_NUM_ITERATIONS-1 do begin | |
| 115 | + | z := DoublePoint( | |
| 116 | + | sqr(z.X) - sqr(z.Y) + c.X, | |
| 117 | + | 2 * z.X * z.Y + c.Y | |
| 118 | + | ); | |
| 119 | + | if sqr(z.X) + sqr(z.Y) > MANDELBROT_LIMIT then begin | |
| 120 | + | Result := false; | |
| 121 | + | // point did escape --> c ei kuulu Mandelbrotin joukkoon | |
| 122 | + | exit; | |
| 123 | + | end; | |
| 124 | + | inc(Iterations); | |
| 125 | + | end; | |
| 126 | + | Result := true; | |
| 127 | + | end; | |
| 128 | + | ``` | |
| 129 | + | ||
| 130 | + | ### Piirtäminen | |
| 131 | + | ||
| 132 | + | Nyt haluamme piirtää Mandelbrotin joukon. Tiedät mitä tehdä? Kyllä - täytyy kirjoittaa vastaava käsittelijä `OnCalculate`. Tapahtumakäsittelijässä kutsutaan funktiota `InMandelbrotSet`. Jos piste siirtyi tapahtumakäsittelijän on Mandelbrotin joukkoon asetaan sen väri mustaksi, jos ei niin jaetaan toistojen määrän suurimman iteraatioiden määrällä ja saadaan arvo väliltä 0 ja 1, joka on vastaava merkintä meidän ColorSource . Oh - mutta miten antaa Mandelbrotin joukon mustan värin pisteitä? Lisätään vain uusi numero ColorSource väripariksi joka yhdistää `clBlack`:n esimerkiksi -1. | |
| 133 | + | ||
| 134 | + | ``` pascal | |
| 135 | + | procedure TForm1.PopulateColorSource; | |
| 136 | + | const | |
| 137 | + | DUMMY = 0.0; | |
| 138 | + | begin | |
| 139 | + | with ColorSource do begin | |
| 140 | + | Clear; | |
| 141 | + | Add(-1.0, DUMMY, '', clBlack); // -1.0 --> musta | |
| 142 | + | Add(0.0, DUMMY, '', clBlue); // 0.0 --> sininen | |
| 143 | + | Add(0.3, DUMMY, '', clRed); // 0.3 --> punainen | |
| 144 | + | Add(1.0, DUMMY, '', clYellow); // 1.0 --> keltainen | |
| 145 | + | end; | |
| 146 | + | end; | |
| 147 | + | ||
| 148 | + | procedure TForm1.Chart1ColorMapSeries1Calculate(const AX, AY: Double; | |
| 149 | + | out AZ: Double); | |
| 150 | + | var | |
| 151 | + | iterations: Integer; | |
| 152 | + | z: TDoublePoint; | |
| 153 | + | begin | |
| 154 | + | if InMandelBrotSet(DoublePoint(AX, AY), iterations, z) then | |
| 155 | + | AZ := -1 | |
| 156 | + | else | |
| 157 | + | AZ := iterations / MANDELBROT_NUM_ITERATIONS; | |
| 158 | + | end; | |
| 159 | + | ``` | |
| 160 | + | ||
| 161 | + | Ja se, mikä on tämän tuloksena - katso vasen kuva: | |
| 162 | + | ||
| 163 | + |   | |
| 164 | + | ||
| 165 | + | Erittäin kiva. Mutta kuten tavallista niin ensimmäinen tulos ei ole vielä paras mahdollinen. Tässä kaksi kohtaa, joita voidaan parantaa: | |
| 166 | + | ||
| 167 | + | - Kuva on **leikattu**. Tämä johtuu siitä, ettei määritelty laskennassa x:n ja y:n aluetta mitä ColorMapSeries käyttää. Yleisesti Mandelbrotin joukko nähdään parhaiten, kun x:n arvot ovat välillä -2,2 ja 0,8, sekä vastaavasti y:n arvot ovat välillä -1.5 ja 1.5. Kirjoita nämä numerot kaavion `Extent`:n kenttiin `XMin, XMax, YMin` ja `YMax` sekä aseta kentät `UseXMin, UseXMax, UseYMin` ja `UseYMin` arvoon `true` jotta nämä akselien raja-arvot aktivoidaan. Voidaan yhtä hyvin käyttää kuvaajan `Extent` ominaisuutta, mutta sitten pitäisi asettaa kaavion `Margins` arvoon 0, ei-täytetyn taustan poistamiseksi lähellä akseleita. | |
| 168 | + | ||
| 169 | + | - Kuva näyttää jotenkin **vääristyneeltä**, jos sitä verrataan kuviin [1](http://en.wikipedia.org/wiki/Mandelbrot_set). Tämä tapahtuu, koska *x* ja *y*-akselilla on eri yksikköpituudet. Vääristymisen välttämiseksi 0:n ja 1:n välinen etäisyys on oltava yhtä suuri molemmille akseleilla. Tietenkin voidaan alustaa lomakkeen leveys ja korkeus oikein, mutta käyttäjä voi muuttaa sen muotoa, ja se vääristäisi kuvaa uudelleen. Kuitenkin `TChart`-komponentilla on käytännöllinen ominaisuus ota käyttöön "neliö" koordinaatisto: aseta `Proportional` arvoon `true`. Tällä asetuksella laajuutta x- ja y-akselit säätyy automaattisesti aina samankokoiseen yksikköön. | |
| 170 | + | ||
| 171 | + | Tulos näiden muutoksien jälkeen näkyy yläpuolella oikeassa kuvassa. Siinä voidaan huomata, että *x*-akselin alue on laajempi kuin oli pyydetty. Tämä on seurausta `Proportional` asetuksesta koska kuvasuhde ei ole ikkunassa yhteensopiva miten *x*- ja *y*-alueet asetetaan kaavion `Extent` ominaisuudessa. | |
| 172 | + | ||
| 173 | + | Ennen kuin jatketaan opetusohjelmaa, niin "kotitehtävänä" voisi olla tälläinen : Muuta ohjelma niin, että Mandelbrotin joukko ei ole musta, mutta näyttää etäisyyden mukaan värit liikeradan origosta kun iterointi keskeytetään. | |
| 174 | + | ||
| 175 | + | ## Zoomaus ja vieritys | |
| 176 | + | ||
| 177 | + | Johdannossa mainittiin, että Mandelbrotin joukko on itsestään samanlainen kuin suurennetussa mittakaavassa. Tämä näkeminen edellyttää zoomausta - ja tämä tehdään opetusohjelman seuraavassa osassa. | |
| 178 | + | ||
| 179 | + | ### Sisäänrakennettu zoomaus | |
| 180 | + | ||
| 181 | + | `TChart` komponentissa on sisäänrakennettuna zoomaus ominaisuudet. Täytyy vain vetää suorakulmio hiirellä ylhäältä-vasemmalta oikeaan alakulmaan alueelle, jota halutaan suurentaa ja pitää hiiren vasenta painiketta alhaalla, vetäessä. Palauta alkuperäinen näkymä vetämällä johonkin toiseen suuntaan tai klikkaa kuvaa. | |
| 182 | + | ||
| 183 | + |    | |
| 184 | + | ||
| 185 | + | Tietenkin voidaan käyttää uutta suurennettua kuvaa zoomata siitä uudestaan ja uudestaan. Kuitenkin jossain zoomaustasolla, akselitunnukset pitenevät ja voi lopulta olla päällekkäisiä. Tämä ei näytä hyvältä. Tarvitsemmeko akselit ollenkaan? Ei - ne saadaan pois päältä menemällä komponenttimuokkaimessa vasemmalle ja ala akselille ja asettamalla niiden omaisuus `Visible` arvoon `false`. | |
| 186 | + | ||
| 187 | + | Mutta ehkä pitäisi olla joitakin viitteitä koosta näyttöikkunassa. Käytössä olevan suurennuksen voidaan näyttää TLabel-komponentilla. Jotta tilaa tulisi muillekin info teksteille myöhemmin tässä opetusohjelmassa, lisätään TPanel komponentti niitä varten. Kohdista tämä "info paneeli" oikealle (`Align` arvoon `alRight`) ja poista sen `Caption`. Jotta saadaan riittävän suuri kaavion uudelleen pitänee muuttaa lomakkeen kokoakin. Lisää label paneelin yläosaan ja nimeä se `LblMagnification`. | |
| 188 | + | ||
| 189 | + | ### Extents | |
| 190 | + | ||
| 191 | + | Miten saada nykyinen suurennus? Näkymä kuvataan TAChart useilla [[TAChart documentation|"extents"]]:llä nämä ovat suorakulmioita kuin `TRect`, mutta kulman pisteet on annettu liukulukuina. Tämä data on tyypiltään `TDoubleRect` ja se on määritelty käännösyksikössä `TAChartUtils`. Esillä on jo ollut funktio `GetFullExtent` on `TChart` joka palauttaa zoomattoman / vierittämättömän näkymän. Zoomauksen tai vierityksen jälkeinen näkymä saadaan `CurrentExtent` tai `LogicalExtent` ominaisuuksilla. Molemmat ovat suorakulmioita ja hyvin samankaltaisia mutta ensinmainittu on hieman suurempi kuin jälkimmäinen, koska se huolehtii myös tarvittavan tilan akselin merkinnöille ja sisemmät kaavio marginaalit. Koska tämä ylimääräinen tila ei oteta huomioon täysimääräisesti, täytyy verrata leveydet full extent / looginen extent ja laskea suurennus. Korkeuksia ei tarvitse miettiä, koska `Proportional` on asettu kaavion. | |
| 192 | + | ||
| 193 | + | On huomattava, että ulottuvuudet (extent) annetaan aina [[TAChart documentation|graph unit]]:na, eli alla olevaan kaavion koordinaatistoon. Koska emme käytä [[TAChart documentation|TChartTransformations]] niin tämä on sama kuin systeemin koordinaatisto näyttäisi akselit (akselikoordinaatit). | |
| 194 | + | ||
| 195 | + | Milloin päivitetään suurennusteksti? Aina kaavion koossa (extent) tapahtuu muutoksia. TChart tarjoaa kaksi tapahtumaa tässä kohdassa: `OnExtentChanged` ja `OnExtentChanging`. Molemmat tapahtumat syntyvät kun koko on jo muuttunut, `OnExtentChanged` kutsutaan piirustuksen rutiinin sisällä, `OnExtentChanging` kutsutaan ennen piirtämistä. Ero on tärkeää, jos tapahtumakäsittelijä aloittaisi uudelleen piirtää kaavion jälleen - tämä voi lukita sovelluksen ... Tässä sovelluksessa ero ei ole merkittävä, joten valitaan `OnExtentChanging`. | |
| 196 | + | ||
| 197 | + | ``` pascal | |
| 198 | + | procedure TForm1.Chart1ExtentChanged(ASender: TChart); | |
| 199 | + | var | |
| 200 | + | cex, fex: TDoubleRect; | |
| 201 | + | factor: double; | |
| 202 | + | begin | |
| 203 | + | cex := Chart1.CurrentExtent; | |
| 204 | + | fex := Chart1.GetFullExtent; | |
| 205 | + | if cex.b.x = cex.a.x then exit; | |
| 206 | + | ||
| 207 | + | factor := (fex.b.x - fex.a.x) / (cex.b.x - cex.a.x); | |
| 208 | + | if factor > 1e6 then | |
| 209 | + | LblMagnification.Caption := Format('Magnification: %.0e', [factor]) | |
| 210 | + | else | |
| 211 | + | LblMagnification.Caption := Format('Magnification: %0.n', [factor]); | |
| 212 | + | end; | |
| 213 | + | ``` | |
| 214 | + | ||
| 215 | + |  | |
| 216 | + | ||
| 217 | + | Tämä on eräs mahdollinen tapahtumakäsittelijän versio. Koska hyvin suuri suurennuskertoimia on vaikea lukea niin siirrytään käyttämään suurennuksen mennessä yli yhden (1) miljoonan eksponentiaalista numeerista merkintätapaa. | |
| 218 | + | ||
| 219 | + | ### Zoomaus kohti ääretöntä ... | |
| 220 | + | ||
| 221 | + | Kokeillaan suurennoksia - kuva oikealla suurennettu yli yhden (1) miljardin kerran (1E9). Ja on mahdollista löytää paikkoja, joissa voit suurennoksia on 1E14 kertaa ennen kuva on "ruma". Jos mietitään tätä numeroa: jos alkuperäinen ei-zoomattu ikkuna olisi 10 cm poikkipituudeltaan - niin tällä suurennuksella se olisi mitattuna 1E13 metriä. Tämä vastaisi kooltaan koko aurinkokuntaa! Ei ole järkevää zoomata enempää, koska me saavuttaneet TAChart sisäisesti käyttämän kaksinkertainen tarkkuuden rajan. Kuitenkin teoriassa, se voi mennä ja ja ... | |
| 222 | + | ||
| 223 | + | ### Kaavion muokkaustyökalujen käyttö | |
| 224 | + | ||
| 225 | + | Jos halutaan siirtää näkymää hieman vasemmalle tai oikealle samalla suurennuksella niin Tätä kutsutaan vierittämiseksi tai panoroinniksi. Kuvan vierittäminen onnistuu vetämällä sitä hiiren oikealla painikkeella. Lazaruksen versiossa 1.0 ei ollut sisäänrakennettua vieritys tukea. Mutta siihenkin sen voi tehdä [[TAChart documentation|kaavion muokkaustyökaluilla]]. | |
| 226 | + | ||
| 227 | + | Tässä ei mennä yksityiskohtiin, mitä kaavion muokkaustyökalut (ChartTools) ovat ja mitä niillä voi yleensä tehdä. Katso sen[[TAChart Tutorial: Chart Tools|opetusohjelmaa]] jos ne eivät ole tuttuja. | |
| 228 | + | ||
| 229 | + |  Aloituksessa lisätään ChartToolSet komponentti lomakkeelle ja linkitetään sen ominaisuus `Toolset` kaavion. Sitten kaksoisklikkaamalla ChartToolSet komponenttia avautuu muokkaustyökalut-ikkuna ja valitaan lisää-painikkeen "takaa" "vieritys vetämällä". Valitse työkalu komponenttimuokkaimessa - se on lapsi ChartToolset objekti puussa - ja asettaa sen ominaisuus `Shift` arvoon `ssRight`. Tämä on hiiren painike joka aktivoi vieritystoiminnan. Voidaan yhdistää myös muita avaimia `Shift` ominaisuuteen, jos halutaan. | |
| 230 | + | ||
| 231 | + | Koska sisäänrakennetut työkalut ovat pois päältä kun käytetään ChartToolset:a niin voidaan myös palauttaa zoomaus valmiudet. - Aivan sama tapa: lisää "Zoomaus vetämällä" ja aseta sen `Shift` ominaisuus arvoon `ssLeft`. | |
| 232 | + | ||
| 233 | + | Jos suoritat ohjelman nyt voit vierittää näkymää vaikka sinulla olisi vanha Lazarus versio. | |
| 234 | + | ||
| 235 | + | ### Zoomaus historia | |
| 236 | + | ||
| 237 | + | Jos zoomata syvemmälle ja syvemmälle Mandelbrotin joukkoa voit mennä yhden tai useamman vaiheen takaisin tutkia yksityiskohtia, jotka eivät enää näy nykyisellä zoomaustasolla. Zoom-historia tallentaa kaikki ulottuvuudet, jotka kerran olivat aktiivisia läpi koko zoomaus- ja vieritysprosessissa. | |
| 238 | + | ||
| 239 | + | Käännösyksiköiden `TATypes` ja `TAChartUtils` tarjoavat luokan `TAChartExtentHistory` mikä sallii toteuttaa zoomaus historian. Koska tämä ei ole komponentti niin on käytettävä koodia. Se luodaan `FormCreate` ja tuhotaan `FormDestroy` tapahtumassa koska zoomaus historia tarvitaan koko ohjelman ajan: | |
| 240 | + | ||
| 241 | + | ``` pascal | |
| 242 | + | procedure TForm1.FormCreate(Sender: TObject); | |
| 243 | + | begin | |
| 244 | + | PopulateColorSource; | |
| 245 | + | Chart1ColorMapseries1.ColorSource := ColorSource; | |
| 246 | + | // Tämä on uutta: | |
| 247 | + | ZoomHistory := TChartExtentHistory.Create; | |
| 248 | + | ZoomHistory.Capacity := 100; | |
| 249 | + | // Historia voi kaapata 100 kertaa, kunnes vanhin tieto katoaa | |
| 250 | + | end; | |
| 251 | + | ||
| 252 | + | procedure TForm1.FormDestroy(Sender: TObject); | |
| 253 | + | begin | |
| 254 | + | ZoomHistory.Free; | |
| 255 | + | end; | |
| 256 | + | ``` | |
| 257 | + | ||
| 258 | + | Aina zoomauksen tai vierityksessa tapahtuvat näkyvän näkymän muutokset kaaviossa lisätään historiaan. Aloitetaan zoomaus jossa käytetään ZoomDragTool:n tapahtumaa `AfterMouseUp` yksinkertaisuuden vuoksi. Olisi myös mahdollista käyttää `OnExtentChanged` tapahtumaa, mutta tässä on oltava varovainen jottaa ohittaa extent muutokset kun perutaan zoomaus (unzooming) - Tästä tarkemmin TAChart mukana olevassa *extent demo*:ssa. | |
| 259 | + | ||
| 260 | + | Huomaa, että extent jo on muuttunut, kun `AfterMouseUp` tapahtuma tulee. Näin ollen, lisätään historiaan kaavion `PrevLogicalExtent` - tämä on näkymä, joka oli aktiivinen ennen kuin extent:ä muutettiin: | |
| 261 | + | ||
| 262 | + | ``` pascal | |
| 263 | + | procedure TForm1.ChartToolset1ZoomDragTool1AfterMouseUp(ATool: TChartTool; | |
| 264 | + | APoint: TPoint); | |
| 265 | + | begin | |
| 266 | + | ZoomHistory.Add(Chart1.PrevLogicalExtent); | |
| 267 | + | end; | |
| 268 | + | ``` | |
| 269 | + | ||
| 270 | + | Vieritys on vähän mutkikkaampi, koska siinä tapahtuu extent muutoksia liikuttaessa hiirtä. MouseUp hetkellä `PrevLogicalExtent` joka on aktiivisena vierityksen alkaessa on jo korvattu useita kertoja. Mutta ratkaisu on yksinkertainen: Tässä voidaan käyttää PanDragTool:n `OnAfterMouseDown` tapahtumaa. | |
| 271 | + | ||
| 272 | + | Olisi kiinnostavaa näyttää infopaneelissa myös montako tasoa on otettu muistiin. `TChartExtentHistory` on sitä vastaava ominaisuus `Count` . Joten, lisätään toinen teksti ("`LblHistoryCount`") on infopaneeliin ja muuttaa kaavion `OnExtentChanged` tapahtumaa lisäämällä seuraava rivi: | |
| 273 | + | ||
| 274 | + | ``` pascal | |
| 275 | + | LblHistoryCount.Caption := Format('History count: %d', [ZoomHistory.Count]); | |
| 276 | + | ``` | |
| 277 | + | ||
| 278 | + | Ja miten palautetaan zoomauksen edellinen taso? Lisäämällä yksi CharTTool lisää. Sen käyttöön ei ole mitään erityisiä vaatimuksia, joten otamme [[TAChart documentation|UserDefinedChartTool]]. Aseta sen `Shift` ominaisuus niin, että työkalu reagoi vain hiiren keskimmäisellä painikkeella. Ja `OnAfterMouseClick` tapahtumakäsittelijässä luetaan viimeinen kohde historiasta (`ZoomHistory.Pop`) ja litetään saatu extent suorakulmio kaavion `LogicalExtent` kohtaan joka säätää näkymän vastaavasti. Tieto poistetaan historiasta pinon lukemisen jälkeen. Historian tietojen määrän näyttö infopaneelissa päivittyy automaattisesti, koska tapahtuma `OnExtentChanged` tapahtuu. Huomaa, että meidän täytyy tarkistaa onko historiatiedot tyhjänä jolloin vältetään poikkeus. | |
| 279 | + | ||
| 280 | + | ``` pascal | |
| 281 | + | procedure TForm1.ChartToolset1UserDefinedTool1AfterMouseUp(ATool: TChartTool; | |
| 282 | + | APoint: TPoint); | |
| 283 | + | begin | |
| 284 | + | if ZoomHistory.Count > 0 then | |
| 285 | + | Chart1.LogicalExtent := ZoomHistory.Pop; | |
| 286 | + | end; | |
| 287 | + | ``` | |
| 288 | + | ||
| 289 | + | Jos halutaan nopeasti palata alkuperäiseen näkymään (suurennuksella 1) voi vetää hiiren vasemmalla painikkeella muuhun suuntaan kuin ylhäältä vasemmalle ja alas oikealle tai vain klikata kaaviota. Koska käyttöön otettiin hiiren keskimmäinen painike zoomauksen perumiseen niin käyttöliittymä voi olla johdonmukaisempi, jos lisätään uusi [[TAChart documentation|UserDefinedChartTool]] ja luovuttaa sen `Shift` ominaisuutta `ssMiddle` ja `ssShift` - usein liitetään `SHIFT` -näppäin toimintaan jolloin tehdään jotain suurempaa, kuten isoja kirjaimia. Siksi yhdistelmä hiiren keskimmäinen näppäin (zoomauksen peruminen) ja`SHIFT` -näppäin näyttää alkuperäisen näkymän. | |
| 290 | + | ||
| 291 | + | Käyttäjän voi kuitenkin olla vaikeaa pitää mielessä kaikki keskeiset yhdistelmät. Siksi lisätään infopaneelin muutamia tekstejä, jossa annetaan ohjeita zoomaukseen, vierittämiseen ja zoomauksen perumiseen. | |
| 292 | + | ||
| 293 | + | Niin, tässä on lopputulos tästä opetusohjelma projektista. Pidä hauskaa! | |
| 294 | + | ||
| 295 | + |  | |
| 296 | + | ||
| 297 | + | ## Lähdekoodi | |
| 298 | + | ||
| 299 | + | Tämän opetusohjelman lähdekoodi löytyy TAChart:n kansiosta *tutorial\mandelbrot*. | |
| 300 | + | ||
| 301 | + | ### project1.lpr | |
| 302 | + | ||
| 303 | + | ``` pascal | |
| 304 | + | program mandelbrot; | |
| 305 | + | ||
| 306 | + | {$mode objfpc}{$H+} | |
| 307 | + | ||
| 308 | + | uses | |
| 309 | + | {$IFDEF UNIX}{$IFDEF UseCThreads} | |
| 310 | + | cthreads, | |
| 311 | + | {$ENDIF}{$ENDIF} | |
| 312 | + | Interfaces, // this includes the LCL widgetset | |
| 313 | + | Forms, main, tachartlazaruspkg | |
| 314 | + | { you can add units after this }; | |
| 315 | + | ||
| 316 | + | {$R *.res} | |
| 317 | + | ||
| 318 | + | begin | |
| 319 | + | RequireDerivedFormResource := True; | |
| 320 | + | Application.Initialize; | |
| 321 | + | Application.CreateForm(TForm1, Form1); | |
| 322 | + | Application.Run; | |
| 323 | + | end. | |
| 324 | + | ``` | |
| 325 | + | ||
| 326 | + | ### main.pas | |
| 327 | + | ||
| 328 | + | ``` pascal | |
| 329 | + | unit main; | |
| 330 | + | ||
| 331 | + | {$mode objfpc}{$H+} | |
| 332 | + | ||
| 333 | + | interface | |
| 334 | + | ||
| 335 | + | uses | |
| 336 | + | Classes, ExtCtrls, StdCtrls, SysUtils, TAGraph, TAFuncSeries, | |
| 337 | + | TASources, Forms, Controls, Graphics, Dialogs, TATypes, TATools, Types; | |
| 338 | + | ||
| 339 | + | type | |
| 340 | + | ||
| 341 | + | { TForm1 } | |
| 342 | + | ||
| 343 | + | TForm1 = class(TForm) | |
| 344 | + | Chart1: TChart; | |
| 345 | + | Chart1ColorMapSeries1: TColorMapSeries; | |
| 346 | + | ChartToolset1: TChartToolset; | |
| 347 | + | ChartToolset1PanDragTool1: TPanDragTool; | |
| 348 | + | ChartToolset1UserDefinedTool1: TUserDefinedTool; | |
| 349 | + | ChartToolset1UserDefinedTool2: TUserDefinedTool; | |
| 350 | + | ChartToolset1ZoomDragTool1: TZoomDragTool; | |
| 351 | + | ColorSource: TListChartSource; | |
| 352 | + | Label1: TLabel; | |
| 353 | + | Label2: TLabel; | |
| 354 | + | Label3: TLabel; | |
| 355 | + | Label4: TLabel; | |
| 356 | + | Label5: TLabel; | |
| 357 | + | Label6: TLabel; | |
| 358 | + | Label7: TLabel; | |
| 359 | + | Label8: TLabel; | |
| 360 | + | Label9: TLabel; | |
| 361 | + | LblMagnification: TLabel; | |
| 362 | + | LblHistoryCount: TLabel; | |
| 363 | + | Panel1: TPanel; | |
| 364 | + | Panel2: TPanel; | |
| 365 | + | Panel3: TPanel; | |
| 366 | + | procedure Chart1ColorMapSeries1Calculate(const AX, AY: Double; | |
| 367 | + | out AZ: Double); | |
| 368 | + | procedure Chart1ExtentChanged(ASender: TChart); | |
| 369 | + | procedure ChartToolset1PanDragTool1AfterMouseDown(ATool: TChartTool; | |
| 370 | + | APoint: TPoint); | |
| 371 | + | procedure ChartToolset1UserDefinedTool1AfterMouseUp(ATool: TChartTool; | |
| 372 | + | APoint: TPoint); | |
| 373 | + | procedure ChartToolset1UserDefinedTool2AfterMouseUp(ATool: TChartTool; | |
| 374 | + | APoint: TPoint); | |
| 375 | + | procedure ChartToolset1ZoomDragTool1AfterMouseUp(ATool: TChartTool; | |
| 376 | + | APoint: TPoint); | |
| 377 | + | procedure FormCreate(Sender: TObject); | |
| 378 | + | procedure FormDestroy(Sender: TObject); | |
| 379 | + | private | |
| 380 | + | ZoomHistory: TChartExtentHistory; | |
| 381 | + | procedure PopulateColorSource; | |
| 382 | + | end; | |
| 383 | + | ||
| 384 | + | var | |
| 385 | + | Form1: TForm1; | |
| 386 | + | ||
| 387 | + | implementation | |
| 388 | + | ||
| 389 | + | {$R *.lfm} | |
| 390 | + | ||
| 391 | + | uses | |
| 392 | + | StrUtils, | |
| 393 | + | TAChartUtils, TAGeometry; | |
| 394 | + | ||
| 395 | + | const | |
| 396 | + | MANDELBROT_NUM_ITERATIONS = 100; | |
| 397 | + | MANDELBROT_ESCAPE_RADIUS = 2.0; | |
| 398 | + | MANDELBROT_LIMIT = sqr(MANDELBROT_ESCAPE_RADIUS); | |
| 399 | + | ||
| 400 | + | function InMandelBrotSet( | |
| 401 | + | AC: TDoublePoint; out AIterations: Integer; out AZ: TDoublePoint): Boolean; | |
| 402 | + | var | |
| 403 | + | j: Integer; | |
| 404 | + | begin | |
| 405 | + | AIterations := 0; | |
| 406 | + | AZ := DoublePoint(0.0, 0.0); | |
| 407 | + | for j := 0 to MANDELBROT_NUM_ITERATIONS - 1 do begin | |
| 408 | + | AZ := DoublePoint( | |
| 409 | + | Sqr(AZ.X) - Sqr(AZ.Y) + AC.X, | |
| 410 | + | 2 * AZ.X * AZ.Y + AC.Y); | |
| 411 | + | if Sqr(AZ.X) + Sqr(AZ.Y) > MANDELBROT_LIMIT then | |
| 412 | + | // point did escape --> AC is not in Mandelbrot set | |
| 413 | + | exit(false); | |
| 414 | + | AIterations += 1; | |
| 415 | + | end; | |
| 416 | + | Result := true; | |
| 417 | + | end; | |
| 418 | + | ||
| 419 | + | { TForm1 } | |
| 420 | + | ||
| 421 | + | procedure TForm1.FormCreate(Sender:TObject); | |
| 422 | + | begin | |
| 423 | + | PopulateColorSource; | |
| 424 | + | ZoomHistory := TChartExtentHistory.Create; | |
| 425 | + | ZoomHistory.Capacity := 100; | |
| 426 | + | end; | |
| 427 | + | ||
| 428 | + | procedure TForm1.FormDestroy(Sender: TObject); | |
| 429 | + | begin | |
| 430 | + | ZoomHistory.Free; | |
| 431 | + | end; | |
| 432 | + | ||
| 433 | + | procedure TForm1.Chart1ColorMapSeries1Calculate( | |
| 434 | + | const AX, AY: Double; out AZ: Double); | |
| 435 | + | var | |
| 436 | + | iterations: Integer; | |
| 437 | + | z: TDoublePoint; | |
| 438 | + | begin | |
| 439 | + | if InMandelBrotSet(DoublePoint(AX, AY), iterations, z) then | |
| 440 | + | AZ := -1 | |
| 441 | + | // or - as a solution to the "homework" exercise: | |
| 442 | + | // AZ := sqrt(sqr(z.x) + sqr(z.y)) / MANDELBROT_ESCAPE_RADIUS | |
| 443 | + | else | |
| 444 | + | AZ := iterations / MANDELBROT_NUM_ITERATIONS; | |
| 445 | + | end; | |
| 446 | + | ||
| 447 | + | procedure TForm1.Chart1ExtentChanged(ASender: TChart); | |
| 448 | + | var | |
| 449 | + | cex, fex: TDoubleRect; | |
| 450 | + | factor: Double; | |
| 451 | + | begin | |
| 452 | + | cex := ASender.CurrentExtent; | |
| 453 | + | fex := ASender.GetFullExtent; | |
| 454 | + | if cex.b.x = cex.a.x then exit; | |
| 455 | + | ||
| 456 | + | factor := (fex.b.x - fex.a.x) / (cex.b.x - cex.a.x); | |
| 457 | + | LblMagnification.Caption := | |
| 458 | + | 'Magnification: ' + Format(IfThen(factor > 1e6, '%.0e', '%0.g'), [factor]); | |
| 459 | + | LblHistoryCount.Caption := Format('History count: %d', [ZoomHistory.Count]); | |
| 460 | + | end; | |
| 461 | + | ||
| 462 | + | procedure TForm1.ChartToolset1PanDragTool1AfterMouseDown( | |
| 463 | + | ATool: TChartTool; APoint: TPoint); | |
| 464 | + | begin | |
| 465 | + | Unused(ATool, APoint); | |
| 466 | + | ZoomHistory.Add(Chart1.PrevLogicalExtent); | |
| 467 | + | end; | |
| 468 | + | ||
| 469 | + | procedure TForm1.ChartToolset1UserDefinedTool1AfterMouseUp( | |
| 470 | + | ATool: TChartTool; APoint: TPoint); | |
| 471 | + | begin | |
| 472 | + | Unused(ATool, APoint); | |
| 473 | + | if ZoomHistory.Count > 0 then | |
| 474 | + | Chart1.LogicalExtent := ZoomHistory.Pop; | |
| 475 | + | end; | |
| 476 | + | ||
| 477 | + | procedure TForm1.ChartToolset1UserDefinedTool2AfterMouseUp( | |
| 478 | + | ATool: TChartTool; APoint: TPoint); | |
| 479 | + | begin | |
| 480 | + | Unused(ATool, APoint); | |
| 481 | + | Chart1.ZoomFull; | |
| 482 | + | end; | |
| 483 | + | ||
| 484 | + | procedure TForm1.ChartToolset1ZoomDragTool1AfterMouseUp( | |
| 485 | + | ATool: TChartTool; APoint: TPoint); | |
| 486 | + | begin | |
| 487 | + | Unused(ATool, APoint); | |
| 488 | + | ZoomHistory.Add(Chart1.PrevLogicalExtent); | |
| 489 | + | end; | |
| 490 | + | ||
| 491 | + | procedure TForm1.PopulateColorSource; | |
| 492 | + | const | |
| 493 | + | DUMMY = 0.0; | |
| 494 | + | begin | |
| 495 | + | with ColorSource do begin | |
| 496 | + | Clear; | |
| 497 | + | Add(-1.0, DUMMY, '', clBlack); | |
| 498 | + | Add( 0.0, DUMMY, '', clBlue); | |
| 499 | + | Add( 0.3, DUMMY, '', clRed); | |
| 500 | + | Add( 1.0, DUMMY, '', clYellow); | |
| 501 | + | end; | |
| 502 | + | end; | |
| 503 | + | ||
| 504 | + | end. | |
| 505 | + | ``` | |
| 506 | + | ||
| 507 | + | ### main.lfm | |
| 508 | + | ||
| 509 | + | ``` pascal | |
| 510 | + | object Form1: TForm1 | |
| 511 | + | Left = 326 | |
| 512 | + | Height = 285 | |
| 513 | + | Top = 155 | |
| 514 | + | Width = 468 | |
| 515 | + | Caption = 'Form1' | |
| 516 | + | ClientHeight = 285 | |
| 517 | + | ClientWidth = 468 | |
| 518 | + | OnCreate = FormCreate | |
| 519 | + | OnDestroy = FormDestroy | |
| 520 | + | LCLVersion = '1.1' | |
| 521 | + | object Chart1: TChart | |
| 522 | + | Left = 4 | |
| 523 | + | Height = 277 | |
| 524 | + | Top = 4 | |
| 525 | + | Width = 288 | |
| 526 | + | AxisList = < | |
| 527 | + | item | |
| 528 | + | Visible = False | |
| 529 | + | Minors = <> | |
| 530 | + | Title.LabelFont.Orientation = 900 | |
| 531 | + | end | |
| 532 | + | item | |
| 533 | + | Visible = False | |
| 534 | + | Alignment = calBottom | |
| 535 | + | Minors = <> | |
| 536 | + | end> | |
| 537 | + | Extent.UseXMax = True | |
| 538 | + | Extent.UseXMin = True | |
| 539 | + | Extent.UseYMax = True | |
| 540 | + | Extent.UseYMin = True | |
| 541 | + | Extent.XMax = 0.8 | |
| 542 | + | Extent.XMin = -2.2 | |
| 543 | + | Extent.YMax = 1.5 | |
| 544 | + | Extent.YMin = -1.5 | |
| 545 | + | Foot.Brush.Color = clBtnFace | |
| 546 | + | Foot.Font.Color = clBlue | |
| 547 | + | Proportional = True | |
| 548 | + | Title.Brush.Color = clBtnFace | |
| 549 | + | Title.Font.Color = clBlue | |
| 550 | + | Title.Text.Strings = ( | |
| 551 | + | 'TAChart' | |
| 552 | + | ) | |
| 553 | + | Toolset = ChartToolset1 | |
| 554 | + | OnExtentChanged = Chart1ExtentChanged | |
| 555 | + | Align = alClient | |
| 556 | + | BorderSpacing.Around = 4 | |
| 557 | + | DoubleBuffered = True | |
| 558 | + | ParentColor = False | |
| 559 | + | object Chart1ColorMapSeries1: TColorMapSeries | |
| 560 | + | ColorSource = ColorSource | |
| 561 | + | Interpolate = True | |
| 562 | + | OnCalculate = Chart1ColorMapSeries1Calculate | |
| 563 | + | StepX = 1 | |
| 564 | + | StepY = 1 | |
| 565 | + | end | |
| 566 | + | end | |
| 567 | + | object Panel1: TPanel | |
| 568 | + | Left = 296 | |
| 569 | + | Height = 285 | |
| 570 | + | Top = 0 | |
| 571 | + | Width = 172 | |
| 572 | + | Align = alRight | |
| 573 | + | BevelOuter = bvNone | |
| 574 | + | ClientHeight = 285 | |
| 575 | + | ClientWidth = 172 | |
| 576 | + | TabOrder = 1 | |
| 577 | + | object Panel2: TPanel | |
| 578 | + | Left = 0 | |
| 579 | + | Height = 213 | |
| 580 | + | Top = 72 | |
| 581 | + | Width = 172 | |
| 582 | + | Align = alClient | |
| 583 | + | BevelOuter = bvNone | |
| 584 | + | ClientHeight = 213 | |
| 585 | + | ClientWidth = 172 | |
| 586 | + | TabOrder = 0 | |
| 587 | + | object Label2: TLabel | |
| 588 | + | Left = 6 | |
| 589 | + | Height = 13 | |
| 590 | + | Top = 8 | |
| 591 | + | Width = 69 | |
| 592 | + | Caption = 'Instructions' | |
| 593 | + | Font.Style = [fsBold] | |
| 594 | + | ParentColor = False | |
| 595 | + | ParentFont = False | |
| 596 | + | end | |
| 597 | + | object Label1: TLabel | |
| 598 | + | Left = 6 | |
| 599 | + | Height = 13 | |
| 600 | + | Top = 37 | |
| 601 | + | Width = 45 | |
| 602 | + | Caption = 'Left-drag' | |
| 603 | + | Font.Style = [fsItalic] | |
| 604 | + | ParentColor = False | |
| 605 | + | ParentFont = False | |
| 606 | + | end | |
| 607 | + | object Label3: TLabel | |
| 608 | + | Left = 6 | |
| 609 | + | Height = 13 | |
| 610 | + | Top = 80 | |
| 611 | + | Width = 53 | |
| 612 | + | Caption = 'Middle-click' | |
| 613 | + | Font.Style = [fsItalic] | |
| 614 | + | ParentColor = False | |
| 615 | + | ParentFont = False | |
| 616 | + | end | |
| 617 | + | object Label4: TLabel | |
| 618 | + | Left = 6 | |
| 619 | + | Height = 13 | |
| 620 | + | Top = 120 | |
| 621 | + | Width = 97 | |
| 622 | + | Caption = 'Middle-click w/SHIFT' | |
| 623 | + | Font.Style = [fsItalic] | |
| 624 | + | ParentColor = False | |
| 625 | + | ParentFont = False | |
| 626 | + | end | |
| 627 | + | object Label5: TLabel | |
| 628 | + | Left = 6 | |
| 629 | + | Height = 13 | |
| 630 | + | Top = 161 | |
| 631 | + | Width = 51 | |
| 632 | + | Caption = 'Right-drag' | |
| 633 | + | Font.Style = [fsItalic] | |
| 634 | + | ParentColor = False | |
| 635 | + | ParentFont = False | |
| 636 | + | end | |
| 637 | + | object Label6: TLabel | |
| 638 | + | Left = 19 | |
| 639 | + | Height = 13 | |
| 640 | + | Top = 56 | |
| 641 | + | Width = 25 | |
| 642 | + | Caption = 'zoom' | |
| 643 | + | ParentColor = False | |
| 644 | + | end | |
| 645 | + | object Label7: TLabel | |
| 646 | + | Left = 22 | |
| 647 | + | Height = 13 | |
| 648 | + | Top = 96 | |
| 649 | + | Width = 81 | |
| 650 | + | Caption = 'unzoom (history)' | |
| 651 | + | ParentColor = False | |
| 652 | + | end | |
| 653 | + | object Label8: TLabel | |
| 654 | + | Left = 19 | |
| 655 | + | Height = 13 | |
| 656 | + | Top = 136 | |
| 657 | + | Width = 54 | |
| 658 | + | Caption = 'full unzoom' | |
| 659 | + | ParentColor = False | |
| 660 | + | end | |
| 661 | + | object Label9: TLabel | |
| 662 | + | Left = 19 | |
| 663 | + | Height = 13 | |
| 664 | + | Top = 177 | |
| 665 | + | Width = 18 | |
| 666 | + | Caption = 'pan' | |
| 667 | + | ParentColor = False | |
| 668 | + | end | |
| 669 | + | end | |
| 670 | + | object Panel3: TPanel | |
| 671 | + | Left = 0 | |
| 672 | + | Height = 72 | |
| 673 | + | Top = 0 | |
| 674 | + | Width = 172 | |
| 675 | + | Align = alTop | |
| 676 | + | BevelOuter = bvNone | |
| 677 | + | ClientHeight = 72 | |
| 678 | + | ClientWidth = 172 | |
| 679 | + | TabOrder = 1 | |
| 680 | + | object LblMagnification: TLabel | |
| 681 | + | Left = 6 | |
| 682 | + | Height = 13 | |
| 683 | + | Top = 8 | |
| 684 | + | Width = 67 | |
| 685 | + | Caption = 'Magnification:' | |
| 686 | + | ParentColor = False | |
| 687 | + | end | |
| 688 | + | object LblHistoryCount: TLabel | |
| 689 | + | Left = 6 | |
| 690 | + | Height = 13 | |
| 691 | + | Top = 29 | |
| 692 | + | Width = 68 | |
| 693 | + | Caption = 'History count:' | |
| 694 | + | ParentColor = False | |
| 695 | + | end | |
| 696 | + | end | |
| 697 | + | end | |
| 698 | + | object ColorSource: TListChartSource | |
| 699 | + | left = 115 | |
| 700 | + | top = 57 | |
| 701 | + | end | |
| 702 | + | object ChartToolset1: TChartToolset | |
| 703 | + | left = 115 | |
| 704 | + | top = 120 | |
| 705 | + | object ChartToolset1ZoomDragTool1: TZoomDragTool | |
| 706 | + | Shift = [ssLeft] | |
| 707 | + | OnAfterMouseUp = ChartToolset1ZoomDragTool1AfterMouseUp | |
| 708 | + | end | |
| 709 | + | object ChartToolset1PanDragTool1: TPanDragTool | |
| 710 | + | Shift = [ssRight] | |
| 711 | + | OnAfterMouseDown = ChartToolset1PanDragTool1AfterMouseDown | |
| 712 | + | end | |
| 713 | + | object ChartToolset1UserDefinedTool1: TUserDefinedTool | |
| 714 | + | Shift = [ssMiddle] | |
| 715 | + | OnAfterMouseUp = ChartToolset1UserDefinedTool1AfterMouseUp | |
| 716 | + | end | |
| 717 | + | object ChartToolset1UserDefinedTool2: TUserDefinedTool | |
| 718 | + | Shift = [ssShift, ssMiddle] | |
| 719 | + | OnAfterMouseUp = ChartToolset1UserDefinedTool2AfterMouseUp | |
| 720 | + | end | |
| 721 | + | end | |
| 722 | + | end | |
| 723 | + | ``` | |
| 724 | + | ||
| 725 | + | ## Samankaltaiset oppimateriaalit | |
| 726 | + | ||
| 727 | + | - [[TAChart Tutorial: Getting started/fi|TAChart opas: Aloitus opas]]: Ensiaskeleet TAChart-kaaviokomponentilla | |
| 728 | + | - [[TAChart Tutorial: Chart Tools]]: johdatus kaaviotyökaluihin (chart tools) | |
| 729 | + | - [[TAChart Tutorial: Function Series/fi|TAChart opas: Funktiokuvaaja]]: esittelee `TFuncSeries` joka seuraa samanlainen käsite kuin `TColorMapSeries` | |
| 730 | + | ||
| 731 | + | --- | |
| 732 | + | *From the Free Pascal wiki, page "TAChart Tutorial: ColorMapSeries, Zooming/fi", as it stood on 2020-02-28 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
