In deze tweedelige serie combineren we het veelzijdige canvaselement met de robuuste jQuery-bibliotheek om een staafgrafiekplug-in te maken. In dit eerste deel gaan we de kernlogica van de plug-in coderen als een zelfstandige versie.
Vandaag gaan we een bargraphing-plug-in maken. Geen gewone plug-in, let wel. We laten jQuery love zien op het canvas-element om een zeer robuuste plug-in te maken.
In dit tweedelige artikel zullen we van het begin af aan beginnen door de logica van de plug-in als een zelfstandig script te implementeren, het in een plug-in te refactureren en dan uiteindelijk al het extra oog-snoepje bovenop de plug-incode toe te voegen. In dit eerste deel gaan we ons alleen bezighouden met het implementeren van de kernlogica.
Heb je een voorbeeld nodig voordat we van start gaan? Alsjeblieft!
Tevreden? Heb je al interesse? Laten we beginnen.
Onze plug-in moet bepaalde basisdingen uitvoeren terwijl hij geen andere dingen doet. Laat me toelichten:
Terwijl we ons verdiepen in de wereld van de allernieuwste, nog steeds niet volledig gespecificeerde technologie, hebben we een aantal afhankelijkheden. Om het canvas-element te laten werken, zijn de meeste moderne browsers voldoende. Maar omdat we gebruik maken van de nieuwe API voor tekstweergave, hebben we nieuwere versies nodig. Browsers die gebruikmaken van de Webkit-engine r433xx en hoger of de Gecko-engine 1.9.1 en hoger moeten uitstekende platforms zijn voor de plug-in. Ik raad aan om een nachtelijke versie van Chromium of Firefox te pakken.
Ik wil graag vermelden dat onze plug-in uitsluitend voor leerdoeleinden is. Deze plug-in is op geen enkele manier bedoeld om andere volwaardige grafische plug-ins zoals Flot, Plotr en dergelijke te vervangen. Ook zal de code zo breed mogelijk zijn. Je zou ver kunnen schrijven, ver efficiëntere code, maar om te leren, zal alles zo ongecompliceerd mogelijk zijn. Voel je vrij om te refactiveren ten gunste van efficiëntie in je productiecode.
OMG WTF HAX
Jaar | verkoop |
---|---|
2009 | 130 |
2008 | 200 |
2007 | 145 |
2006 | 140 |
2005 | 210 |
2004 | 250 |
2003 | 170 |
2002 | 215 |
2001 | 115 |
2000 | 135 |
1999 | 110 |
1998 | 180 |
1997 | 105 |
Niets bijzonders aan de markup. Ik zal hoe dan ook een snel overzicht doen.
Voordat ik Javascript start, geef ik uitleg over het canvas-coördinatensysteem. De linkerbovenhoek fungeert als de oorsprong, d.w.z. (0, 0). Punten worden vervolgens gemeten ten opzichte van de oorsprong, waarbij x rechts toeneemt en y langs links toeneemt. Voor de wiskundig ingestelde mensen werken we effectief in het 4e kwadrant behalve dat we de absolute waarde van y in plaats van de negatieve waarde nemen. Als je met afbeeldingen in andere talen hebt gewerkt, zou je hier thuis moeten zijn.
Reinigingsroutine van canvas wordt uitgebreid door het artikel gebruikt om de balken, het raster en enkele andere elementen weer te geven. Met dat in gedachten, laten we deze routines kort bekijken.
Van de drie beschikbare routines zullen we de fillRect en strokeRect methoden. De fillRect methode vult eigenlijk de gerenderde rechthoek terwijl de strokeRect methode strijkt alleen de rechthoeken. Anders dan dat, nemen beide methoden dezelfde parameters.
Zoals altijd raad ik u ten zeerste aan om de broncode te downloaden en ter referentie bij de hand te houden. Het is gemakkelijker om naar de grote afbeelding te kijken en elke functie stuk voor stuk te analyseren dan elke functie afzonderlijk te bekijken en vervolgens de grote afbeelding in gedachten te creëren.
var barSpacing = 20, barWidth = 20, cvHeight = 220, numYlabels = 8, xOffset = 20, gWidth = 550, gHeight = 200; var maxVal, gValues = [], xLabels = [], yLabels = []; var cv, ctx;
Deze variabelen bevatten hard gecodeerde waarden om ons te helpen bij de positionering en lay-out van de grafiek en de afzonderlijke staven.
Met de krachtige selector-engine van jQuery wordt het voor ons heel gemakkelijk om de gegevens te krijgen die we nodig hebben. Hier hebben we een aantal manieren om toegang te krijgen tot de noodzakelijke elementen. Laat me er een paar hieronder uitleggen:
$ ("tr"). children ("td: odd"). each (function () // code here);
De eenvoudigste manier om toegang te krijgen tot de benodigde rijen. Zoekt naar een tr element en vervolgens toegang tot elkaar td element. Misplaatst als u meer dan één tabel op uw pagina heeft.
$ ("# data"). find ("td: odd"). each (function () // code here);
Een veel rechtlijniger manier. We geven het ID van de tabel door en openen vervolgens elke andere rij.
$ ("# data tr td: odd"). each (function () // code here);
Hetzelfde als hierboven, behalve dat we de syntaxis van de CSS-stijlselecteerder gebruiken.
$ ("# data tr td: nth-child (2)"). each (function () // code here);
De versie die we vandaag gaan gebruiken. Op deze manier is het een stuk beter als we gegevens uit een andere rij of, indien nodig, uit meerdere rijen moeten halen.
De definitieve versie ziet er als volgt uit:
function grabValues () // Toegang tot de vereiste tabelcel, uitpakken en de waarde ervan toevoegen aan de waardenreeks. $ ("# data tr td: nth-child (2)"). each (function () gValues.push ($ (this) .text ());); // Open de vereiste tabelcel, extraheer en voeg de waarde toe aan de array xLabels. $ ("# data tr td: nth-child (1)"). each (function () xLabels.push ($ (this) .text ()););
Niets ingewikkelds hier. We gebruiken het hierboven vermelde codefragment om de waarde van de tabelcel toe te voegen aan de gValues matrix. Vervolgens doen we hetzelfde, behalve dat we de eerste tabelcel openen om het vereiste label voor de x-as te extraheren. We hebben de data-extractielogica ingekapseld in zijn eigen functie voor hergebruik en leesbaarheid van code.
function initCanvas () // Probeer toegang te krijgen tot het canvas-element en een fout te genereren als deze niet beschikbaar is cv = $ ("# graph"). get (0); if (! cv) terug; // Probeer een 2D-context voor het canvas te krijgen en een fout te genereren als ctx = cv.getContext ('2d') niet mogelijk is; if (! ctx) terug;
Routine canvas initialisatie. Eerst proberen we het canvas-element zelf te openen. We gooien een foutmelding als dit niet lukt. Vervolgens proberen we een verwijzing naar de 2D-renderingcontext te verkrijgen via de getContext methode en gooi een fout als dit niet lukt.
Voordat we ingaan op de daadwerkelijke weergave van de grafiek zelf, moeten we een aantal hulpprogramma-functies bekijken die ons enorm helpen in het proces. Elk van hen zijn klein op zichzelf, maar zal op grote schaal worden gebruikt in onze code.
functie maxValues (arr) maxVal = 0; voor (i = 0; iEen kleine functie die itereert via de gepasseerde array en de maxval variabel. Houd er rekening mee dat we de maximale waarde met 10% opblazen voor speciale doeleinden. Als de maximumwaarde blijft zoals die is, raakt de balk die de bovenste waarde vertegenwoordigt de rand van het canvaselement aan, wat we niet willen. Met dat in gedachten, wordt een verhoging van 10% uitgegeven.
De waarde normaliseren
functie schaal (param) return Math.round ((param / maxVal) * gHeight);Een kleine functie om de geëxtraheerde waarde te normaliseren met betrekking tot de hoogte van het canvaselement. Deze functie wordt veel gebruikt in andere functies en rechtstreeks in onze code om de waarde uit te drukken als een functie van de hoogte van het canvas. Neemt een enkele parameter.
De X-coördinaat retourneren
functie x (param) return (param * barWidth) + ((param + 1) * barSpacing) + xOffset;Retourneert de x-ordinaat naar de fillRect om ons te helpen bij het positioneren van elke afzonderlijke balk. Ik zal dit een beetje meer in detail uitleggen wanneer het wordt gebruikt.
De Y-coördinaat retourneren
functie y (param) terug gHeight - schaal (param);Retourneert de y-ordinaat naar de fillRect methode om ons te helpen bij het positioneren van elke afzonderlijke balk. Meer uitleg iets later.
De breedte terugzetten
functie breedte () return barWidth;Retourneert de breedte van elke afzonderlijke balk.
Terugkeren van de hoogte
functiehoogte (param) return scale (param);Retourneert de hoogte van de balk die moet worden getekend. Gebruikt de schaal functie om de waarde te normaliseren en vervolgens terug te geven aan de beller.
De X-as-labels tekenen
functie drawXlabels () ctx.save (); ctx.font = "10px 'arial'"; ctx.fillStyle = "# 000"; voor (index = 0; indexEen eenvoudige functie om de labels van de x-as te renderen. We slaan eerst de huidige staat van het canvas op inclusief alle weergave-instellingen, zodat alles wat we in de functies doen nooit uitlekt. Vervolgens stellen we de grootte en het lettertype van de labels in. Vervolgens herhalen we door de xLabels array en bel de fillText methode elke keer om het label weer te geven. Wij gebruiken de X functie om ons te helpen bij het positioneren van de labels.
Y-aslabels tekenen
functie drawYlabels () ctx.save (); voor (index = 0; indexEen iets meer uitgebreide functie. We slaan eerst de huidige staat van het canvas op en gaan dan verder. Vervolgens delen we maxval's waarde in n elementen waar de variabele numYlabels dicteert n. Deze waarden worden vervolgens toegevoegd aan de yLabels matrix. Nu, zoals hierboven getoond, de fillText methode wordt gebruikt om de individuele labels te tekenen met de Y functie die ons helpt bij de positionering van elk individueel label.
We maken een nul onderaan het canvas om het tekenen van de Y-labels te voltooien.
De grafiek tekenen
functie drawGraph () for (index = 0; indexDe functie die de eigenlijke balken in het staafdiagram tekent. Herhaalt door de gValues array en rendert elke afzonderlijke balk. Wij gebruiken de fillRect methode om de balken te tekenen. Zoals hierboven uitgelegd, heeft de methode vier parameters nodig, waarvan elk wordt verzorgd door onze nutsfuncties. De huidige index van de lus wordt doorgegeven aan onze functies als parameters, samen met de werkelijke waarde die in de array wordt vastgehouden, indien nodig.
De X functie retourneert de x-coördinaat van de balk. Telkens wordt het verhoogd met de waarde van de som van BarWidth en barSpacing variabelen.
De Y functie berekent het verschil tussen de hoogte van het canvaselement en de genormaliseerde gegevens en retourneert het. Ik weet dat dit een beetje klinkt, maar dit komt door het feit dat de y-waarden op het canvasraster toenemen bij het omlaag gaan, terwijl in onze grafiek de y-waarden toenemen bij het omhoog gaan. We moeten dus een beetje werk doen om het te laten functioneren zoals we dat willen.
De breedte functie retourneert de breedte van de afzonderlijke balken zelf.
De hoogte functie retourneert gewoon de genormaliseerde waarde die wordt gebruikt als de hoogte van de balk die moet worden getekend.
Samenvatting
In dit eerste deel hebben we de basislogica van onze plug-in geïmplementeerd als een stand-alone versie met blote botten uiterlijk en functies. We hebben het canvas-coördinatensysteem, de rechthoek-renderingmethoden, wat handige gegevensextractie met behulp van de aangeboren awesomeness van jQuery [heb ik gezegd hoeveel ik jQuery leuk vond?] Bekeken, hoe de labels zijn getekend en uiteindelijk gekeken naar de logica achter de rendering van de grafiek zelf.
Aan het einde van dit artikel zou de uitvoer er zo uit moeten zien.
Volgende!
Onze huidige implementatie ontbreekt eigenlijk. Het ziet er saai uit, kan niet meerdere grafieken maken op dezelfde pagina, en laten we eerlijk zijn, is nogal spartaans aan de voorkant van de functies. Dat gaan we volgende week aanpakken. In het volgende artikel zullen we:
- Refactor onze code om er een volwaardige jQuery-plugin van te maken.
- Voeg wat eye candy toe.
- Inclusief een aantal handige kleine functies.
Vragen? Kritiek? Lof? Voel je vrij om de reacties te raken. Bedankt voor het lezen en als je klaar bent, ga je verder naar deel twee!
- Volg ons op Twitter, of abonneer je op de NETTUTS RSS-feed voor meer dagelijkse webontwikkelingen, tuts en artikelen.