Tag cloud
Hoi hoi,
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:
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...
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...
Ik heb dit nog niet getest, maar zit gewoon even hard op met je mee te denken:
- 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.
- 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.
Bedankt, ik ben al een stuk verder. Alleen komt alles nu ruim boven de 100%, en dan zijn de waardes niet juist meer denk ik. Althans, dan krijg ik veel te veel van hetzelfde. Dit zijn m'n waardes op jouw manier:
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)
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)
Zet het maximaal aantal dat gehaald is op 100%. Probleem bij dit soort dingen is dat als je heel veel opties hebt, alle opties redelijk dicht bij de 0% komen te liggen.
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.
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.
Laat dan maar een zien hoe je tot dat resultaat bent gekomen.
Uitgaande van de waarden in je openingspost
totaal = 41
Dan krijg je voor wit: 19.51219512
Uitgaande van de waarden in je openingspost
totaal = 41
Dan krijg je voor wit: 19.51219512
Het klopte inderdaad niet wat ik deed, ik krijg nu voor wit hetzelfde:
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)
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.
Hierbij de werking van de tagcloud die ik heb gemaakt. Helaas heb ik op dit moment geen voorbeeld online...
Ik heb het volgende als CSS:
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:
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:
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:
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:
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).
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?
Ik heb maar 1 tabel met tags. De andere bevat alleen de gegevens waneer de tags gebruikt zijn. Werkt met een 1-op-n relatie. De andere bevat alleen de inhoud; dus de tags. En die heeft dan weer meerdere 1-op-n relaties naar pagina_tag, actueel_tag.
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.
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. :-)
In principe kan je dat er gewoon uithalen. Ik haal het op met datums, omdat ik alleen het actieve gebruik van tags wil hebben (de tags waarop de laatste 2 maanden is geklikt).
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.
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!
Kan je mij een dump sturen van je tabel, incl. de CREATE syntax? Dan kan ik kijken of ik die van Jou en mij kan samenvoegen.
Mag wat mij betreft als tekst in dit topic, per PM of als download ergens.
Mag wat mij betreft als tekst in dit topic, per PM of als download ergens.
Verstuurd als PM!
Het lijkt mij beter om het zo te doen:
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);
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 -
Met jouw voorbeeld zijn alle woorden even groot, 21px om precies te zijn.
Wat overigens ook logisch is, want de formule is altijd hetzelfde in m'n foreach.
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> ';
}
?>
$aantal_bepalen is het aantal dat het woord voorkomt. Dus dat gaat zo niet werken. Hier een werkend voorbeeld:
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.
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 -




