Tag cloud
Ik ben voor de website van m'n vriendin bezig met een tag cloud. Per artikel worden er tags toegevoegd, die dan allemaal in de database komen te staan. Als ik ze op in de tag cloud wil ophalen, dan groepeer ik alle tags en staat daarachter het aantal keer dat die tag voorkomt.
Dit doe ik met de volgende query:
Dit is m'n output:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
tag aantal
bloem 2
bruin 4
figuurtje 1
goud 1
grijs 1
kerst 3
nagellakpennen 1
paars 4
panterprint 1
patroon 1
randje 1
rood 2
rudolf 1
strak 1
strik 1
tekenen 1
wit 8
zilver 3
zwart 4
bloem 2
bruin 4
figuurtje 1
goud 1
grijs 1
kerst 3
nagellakpennen 1
paars 4
panterprint 1
patroon 1
randje 1
rood 2
rudolf 1
strak 1
strik 1
tekenen 1
wit 8
zilver 3
zwart 4
Nu wil ik natuurlijk dat de tag met het grootste aantal (wit in dit geval) het grootst is. Ik heb link classes w1 t/m w8, waarin w8 de grootste is. Ik heb al een tijdje zitten denken hoe ik dit wil doen, en ik wil van iedere grootte ongeveer 10%. Hoe moet ik dit doen?
Ik krijg het gewoon niet voor elkaar om me voor te stellen hoe ik dit zou moeten doen.
Bedankt...
- Je telt alle aantallen bij elkaar op. (COUNT(*) AS total ofzo)
- Je berekend het aantal procent van het totaal dat de tag heeft. (met zwart is dat (100 / totaal) * 4
- 100% in 8 stukken verdelen wordt ong. 11%. Dus w1 = 11%, w2 = 22%, ..., w8 = 88%
- Je kijkt in welk gebied het procent van de tag ligt.
bloem (10.5263157895)
bruin (21.0526315789)
figuurtjes (5.26315789474)
goud (5.26315789474)
grijs (5.26315789474)
kerst (15.7894736842)
nagellakpennen (5.26315789474)
paars (21.0526315789)
panterprint (5.26315789474)
patroon (5.26315789474)
randje (5.26315789474)
rood (10.5263157895)
rudolf (5.26315789474)
strak (5.26315789474)
strik (5.26315789474)
tekenen (5.26315789474)
wit (42.1052631579)
zilver (15.7894736842)
zwart (21.0526315789)
(op alfabetische volgorde dit keer)
Je ziet het in jouw lijst al, de hoogste zit nog maar op 42%.
Als je echter de maximale waarde (in dit geval dus 8) neemt als maximum heb je dus altijd ook de hoogste categorie ook te pakken.
Uitgaande van de waarden in je openingspost
totaal = 41
Dan krijg je voor wit: 19.51219512
bloem (4.87804878049)
bruin (9.75609756098)
figuurtjes (2.43902439024)
goud (2.43902439024)
grijs (2.43902439024)
kerst (7.31707317073)
nagellakpennen (2.43902439024)
paars (9.75609756098)
panterprint (2.43902439024)
patroon (2.43902439024)
randje (2.43902439024)
rood (4.87804878049)
rudolf (2.43902439024)
strak (2.43902439024)
strik (2.43902439024)
tekenen (2.43902439024)
wit (19.512195122)
zilver (7.31707317073)
zwart (9.75609756098)
Iemand toevallig enig idee? :)
Begin eens met een loop door je resultaten en maak de tekst-grootte in pixels het percentage (afgerond).
Lijkt me niet verstandig, dan komen er woorden van twee pixels.
Maak je een controle die alles onder de 6px overslaat.
Ik heb het volgende als CSS:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
div.tagcloud {
/* border, background, etc van de div */
}
div.tagcloud a.tag1 {
font-size: 8px;
}
div.tagcloud a.tag2 {
font-size: 10px;
}
/*
Dit gaat door tot tag5, waarbij font-size steeds groter word
en er ook wat kleuren wijzigen.
*/
/* border, background, etc van de div */
}
div.tagcloud a.tag1 {
font-size: 8px;
}
div.tagcloud a.tag2 {
font-size: 10px;
}
/*
Dit gaat door tot tag5, waarbij font-size steeds groter word
en er ook wat kleuren wijzigen.
*/
Voor de opslag van tags gebruik ik een tabel met tags (tabel: tag, kolommen: tag_id, tag_tag, tag_url) en een tabel met het gebruik (tabel: tag_gebruik, kolommen: tge_id, tge_tag_id, tge_datumtijd), deze wordt dus gevuld als een bezoeker op een tag bij een pagina of in de tagcloud klikt.
Als ik mijn tagcloud ga uitlezen gebruik ik een query om de 50 meest gebruikte tags van de afgelopen twee maanden op te halen:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$sql = "SELECT
COUNT(tge_tag_id) as tge_aantal,
tag_tag,
tag_url
FROM
tag_gebruik,
tag
WHERE
tge_tag_id = tag_id
AND
tge_datumtijd > DATE_SUB(CURDATE(), INTERVAL 2 MONTH)
GROUP BY
tge_tag_id
ORDER BY
COUNT(tge_tag_id) DESC
LIMIT
0,50";
?>
$sql = "SELECT
COUNT(tge_tag_id) as tge_aantal,
tag_tag,
tag_url
FROM
tag_gebruik,
tag
WHERE
tge_tag_id = tag_id
AND
tge_datumtijd > DATE_SUB(CURDATE(), INTERVAL 2 MONTH)
GROUP BY
tge_tag_id
ORDER BY
COUNT(tge_tag_id) DESC
LIMIT
0,50";
?>
Na het uitvoeren van die query maak ik een lege array aan ($aTags) en de twee variabelen $laagste (waarde: null) en $hoogste (waarde: 0). Waarom is $laagste null, dat komt omdat ik anders nooit de werkelijk laagste (minst gebruikte tag) kan achterhalen, want het kan nooit lager zijn dan 0, zie ook de volgende loop.
Vervolgens loop ik door de resultaten van de query:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
<?php
while($row = mysql_fetch_assoc($res)) {
// Laagste bepalen
if($laagste == NULL) $laagste = $row['tge_aantal'];
else if($laagste > $row['tge_aantal']) $laagste = $row['tge_aantal'];
// Hoogste bepalen
if($row['tge_aantal'] > $hoogste) $hoogste = $row['tge_aantal'];
// Toevoegen aan de array
$aTags[] = array('tag_tag' => $row['tag_tag'],'tag_url' => $row['tag_url'], 'tge_aantal' => $row['tge_aantal']);
}
?>
while($row = mysql_fetch_assoc($res)) {
// Laagste bepalen
if($laagste == NULL) $laagste = $row['tge_aantal'];
else if($laagste > $row['tge_aantal']) $laagste = $row['tge_aantal'];
// Hoogste bepalen
if($row['tge_aantal'] > $hoogste) $hoogste = $row['tge_aantal'];
// Toevoegen aan de array
$aTags[] = array('tag_tag' => $row['tag_tag'],'tag_url' => $row['tag_url'], 'tge_aantal' => $row['tge_aantal']);
}
?>
Nu heb ik dus in $laagste het aantal van de tag die het minst gebruikt is en in $hoogste die het meest gebruikt is. De array $aTag is nu gevuld met die 50 tags, en de data die nodig is om hem te laten zien/werken.
Hierna gooi ik de array $aTag overhoop, zodat de tagcloud er 'nooit' hetzelfde uitziet. Dit doe ik met shuffle.
Dan moet ik uitrekenen met welke stappen de tags een andere CSS-class krijgen. Dit bepaal ik op de volgende manier:
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?php
$aStap = array(); // Lege array om de stappen in te bewaren
$maxStappen = 5; // Er zijn dus 5 CSS-classes
$stappen = floor(($hoogste-$laagste) / $maxStappen); // Uitrekenen hoeveel er tussen stappen zit
for($i=1;$i<=$maxStappen;$i++) $aStap[$i] = $i*$stappen+$laagste; // En de array vullen met het begin van de stap
?>
$aStap = array(); // Lege array om de stappen in te bewaren
$maxStappen = 5; // Er zijn dus 5 CSS-classes
$stappen = floor(($hoogste-$laagste) / $maxStappen); // Uitrekenen hoeveel er tussen stappen zit
for($i=1;$i<=$maxStappen;$i++) $aStap[$i] = $i*$stappen+$laagste; // En de array vullen met het begin van de stap
?>
Dus, als $hoogste 86 is en $laagste 12, dan is $stappen 14. En $aStap is dan het volgende:
Dan is het tijd om $aTag en $aStap te gaan matchen zodat de tags de juiste class krijgen:
Code (php)
Nu ik er zo naar zit te kijken heb ik het idee dat het nog wel iets simpeler kan, maar ik hoop dat ik je zo op een idee gebracht heb.
Edit:
Bovenstaande komt uit een nieuw project, maar ik bedenk met net dat die is gebaseerd op de tagcloud van http://pointtopoint.nl/ (waar de CSS van de cloud niet echt optimaal is).
Gewijzigd op 10/01/2012 22:54:54 door Elwin - Fratsloos
Knap gemaakt. Waarom heb je overigens twee tabellen met tags?
Eerst gebruikte ik altijd gewoon een TEXT met daarin de tags komma-gescheiden, maar dat werkte niet naar behoren. Toen ben ik het gaan scheiden en kwam ik uiteindelijk op deze methode.
Heb je misschien een simpeler voorbeeld? Je hebt in jouw code een heel systeem met datums en alles erop en eraan, ik hoef alleen maar een simpele tag cloud. :-)
Het belangrijkste is de laatste drie PHP-blokken (dus niet dat array-blok). Daarin leg ik uit hoe ik bepaal welke CSS-class een tag moet hebben.
Maar ik zat er al aan te denken om hier een mini-tutorial over te schrijven, heb ik ook weer wat content voor mijn eigen site, die ik weer wat probeer up-te-daten. :)
Dat zal denk ik in het weekend worden.
Dan wacht ik rustig af, dit gaat mij namelijk nog even boven m'n pet. Toch bedankt!
Mag wat mij betreft als tekst in dit topic, per PM of als download ergens.
Verstuurd als PM!
Bepaal het minimaal en maximaal aantal. Dus in jouw voorbeeld 1 en 8.
Bepaal vervolgens de minimale lettergrootte en maximale lettergrootte. Bijvoorbeeld 10 en 30 pixels.
Dus:
$aantal_bepalen = 5; // Voor 5 keer wil je de lettergrootte bepalen
$aantal_min = 1;
$aantal_max = 8;
$font_min = 10;
$font_max = 30;
Formule:
$lettergrootte = $font_min + round((($font_max - $font_min) / ($aantal_max - $aantal_min)) * ($aantal_bepalen - $aantal_min));
Op deze manier heb je altijd een minimale en maximale grootte en daarbinnen variëert de lettergrootte.
Wat je dan kan doen is het resultaat van je query in een array zetten met de tagnaam als key (aangezien deze altijd uniek is) en het aantal als value, dus:
$array = array('wit' => 20, 'blauw' => '10');
Vervolgens is met min() en max() simpel het maximale en minimale aantal uit de array te halen:
$min = min($array);
$max = max($array);
Gewijzigd op 12/01/2012 19:21:19 door Arjan -
Wat overigens ook logisch is, want de formule is altijd hetzelfde in m'n foreach.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
$tags = array();
$aantal_bepalen = 5; // Voor 5 keer wil je de lettergrootte bepalen
$aantal_min = 1;
$aantal_max = 8;
$font_min = 10;
$font_max = 30;
while ($tag = mysql_fetch_assoc($sql))
{
$tags[$tag['tag']] = $tag['aantal'];
}
$min = min($tags);
$max = max($tags);
foreach ($tags as $tag => $aantal)
{
$lettergrootte = $font_min + round((($font_max - $font_min) / ($aantal_max - $aantal_min)) * ($aantal_bepalen - 1));
echo '<a href="#" style="font-size: '.$lettergrootte.'px">'.$tag.'</a> ';
}
?>
$tags = array();
$aantal_bepalen = 5; // Voor 5 keer wil je de lettergrootte bepalen
$aantal_min = 1;
$aantal_max = 8;
$font_min = 10;
$font_max = 30;
while ($tag = mysql_fetch_assoc($sql))
{
$tags[$tag['tag']] = $tag['aantal'];
}
$min = min($tags);
$max = max($tags);
foreach ($tags as $tag => $aantal)
{
$lettergrootte = $font_min + round((($font_max - $font_min) / ($aantal_max - $aantal_min)) * ($aantal_bepalen - 1));
echo '<a href="#" style="font-size: '.$lettergrootte.'px">'.$tag.'</a> ';
}
?>
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
// mysql query hier
$tags = array();
while ($tag = mysql_fetch_assoc($sql))
{
$tags[$tag['tag']] = $tag['aantal'];
}
if(is_array($tags) AND count($tags) > 0) {
$aantal_min = min($tags);
$aantal_max = max($tags);
$font_min = 10;
$font_max = 30;
foreach($tags AS $key => $value) {
$lettergrootte = $font_min + round((($font_max - $font_min) / ($aantal_max - $aantal_min)) * ($value - $aantal_min));;
echo '<span style="font-size: '.$lettergrootte.'px;"><a href="/zoeken?tag='.urlencode($key).'">'.htmlspecialchars($key).'</a></span> ';
}
}
?>
// mysql query hier
$tags = array();
while ($tag = mysql_fetch_assoc($sql))
{
$tags[$tag['tag']] = $tag['aantal'];
}
if(is_array($tags) AND count($tags) > 0) {
$aantal_min = min($tags);
$aantal_max = max($tags);
$font_min = 10;
$font_max = 30;
foreach($tags AS $key => $value) {
$lettergrootte = $font_min + round((($font_max - $font_min) / ($aantal_max - $aantal_min)) * ($value - $aantal_min));;
echo '<span style="font-size: '.$lettergrootte.'px;"><a href="/zoeken?tag='.urlencode($key).'">'.htmlspecialchars($key).'</a></span> ';
}
}
?>
Zoals je ziet raad ik je aan om geen classes te gebruiken maar gewoon 'hardcoded' in de html de lettergrootte te bepalen. Hierdoor heb je altijd een mooie tagcloud met een minimale en maximale lettergrootte.
Gewijzigd op 12/01/2012 19:46:59 door Arjan -