Page 1 sur 1

Frise chronologique & CSS

Posté : 20 juil. 2016, 02:49
par finipe
Bonjour à tous,

Je réalise un projet de frise chronologique qui reprend des compositeurs dans une base de données et génère la frise automatiquement. Ça fonctionne pas mal, mais je bute sur un problème de mise en page.

Voici le code :
echo "<div id='FRISE'>";

// -- CADRE CHRONOLOGIQUE
echo "<div id='CHRONO_SIECLES'>";
for($i=1400 ; $i<=2000 ; $i+=100) echo "<p>".$i."</p>";

// -- AFFICHAGE DES COMPOSITEURS DEPUIS LA BASE
for($i=1 ; $i<=7 ; $i++)
{
	$result = mysqli_query($DB, "SELECT * FROM compositeurs WHERE periode='".$i."' ORDER BY naissance ASC");
	while($row = mysqli_fetch_array($result))
	{
		// Naissance et mort du compositeur
		// --> Si le compositeur n'est pas mort, la fin de la barre correspond à l'année en cours
		if(empty($row['mort']))	$fin = date(Y);
		else					$fin = intval($row['mort']);
		$debut = intval($row['naissance']);

		// Durée de vie
		$longevite = $fin - $debut;

		// Naissance du compositeur à partir de l'origine (année 1400)
		// Multiplicateur pixels = 4
		$left = ($debut - 1400)*4;
		echo "<div class='CHRONO_COMPO' style='margin-left:".$left."px; color:".$__PERIODE[intval($row['periode'])][2]."; background-color:".$__PERIODE[intval($row['periode'])][1]."; width:".($longevite*4)."px;'>".$row['prenom']." ".$row['nom']."<br />".$row['naissance']."-".$row['mort']."</div>";
	}
}
echo "</div>"; // Fin #CHRONO_SIECLES
echo "</div>"; // Fin #FRISE


Et le CSS qui va avec...

Code : Tout sélectionner

#FRISE { width:2800px; margin:0; font-family:Georgia, serif; } #CHRONO_SIECLES { background:#EFEFEF url(Images/fond_frise.png); width:2800px; position:absolute; z-index:-1; overflow:auto; } #CHRONO_SIECLES p { font-size:1.5em; margin:0 0 20px 0; padding-left:2px; width:398px; display:inline-block; } .CHRONO_COMPO { margin-top:3px; cursor:pointer; text-align:center; font-size:0.7em; height:36px; display:block; color:black; line-height:18px; } .CHRONO_COMPO:hover { box-shadow:0px 0px 0px 2px #000000 inset; }

Et enfin, le résultat obtenu :
Image

Je suis plutôt satisfait, mais je voudrais que les compositeurs ne se succèdent pas les uns en dessous des autres, sans quoi au bout d'un moment la frise va devenir trop haute et impraticable.

Comment faire pour que :
- si les dates se chevauchent, les barres des compositeurs se décalent l'une en dessous de l'autre ?
- et si les dates ne se chevauchent pas, la nouvelle barre se place au même niveau qu'une précédente ?
(par exemple, dans la copie d'écran ci-dessous, la barre de Claudio Monteverdi se placerait au même niveau que celle de Clément Janequin, puis Lully au niveau de Palestrina, Purcell au niveau de Janequin et Monteverdi, etc.)

Image

Merci pour votre aide !

Re: Frise chronologique & CSS

Posté : 20 juil. 2016, 10:13
par @rthur
Bonjour,

A mon avis ce n'est pas possible à réaliser en 100% CSS, tu vas probablement être obligé de concevoir un algorithme (en PHP ou en JS) pour calculer pour chaque nouvel élément sur quel ligne tu dois l'afficher en fonction de la place disponible.
C'est bcp + complexe à faire que ce que tu as fait à l'heure actuelle

Re: Frise chronologique & CSS

Posté : 20 juil. 2016, 12:57
par finipe
Arg... Ok, merci pour la réponse, ça va m'éviter de perdre du temps à essayer des trucs en CSS.
Pour ce qui est de l'algorithme, je vois à peu près comment faire.
(Si ça roule, je posterai ici au cas où y aurait des gens intéressés)

Re: Frise chronologique & CSS

Posté : 20 juil. 2016, 14:03
par Ryle
Bonjour,

Pour l'algo, ce n'est pas nécessairement très compliqué à mon avis, en tout cas je pense qu'il existerait une solution assez simple avec une boucle et un tableau de tes compositeurs.

Comme ci-dessus tu récupères tes compositeurs par ordre chronologique et tu alimentes un tableau php avec cette liste. Tu vas ensuite parcourir ce tableau à l'aide d'une boucle, tant qu'il y a des éléments dans le tableau.

Il te suffit alors d'afficher le premier de tes compositeurs (et de le retirer du tableau), puis de regarder si le suivant le "chevauche" ou non. S'il ne le chevauche pas, on l'affiche à la suite sur la même ligne ; s'il le chevauche on passe au suivant et on recommence en supprimant du tableau ceux qui ont été affichés.

Une fois arrivé à la fin du tableau, celui-ci ne contient plus que les compositeurs qui n'ont pas encore été affichés. On attaque alors une nouvelle ligne et on recommence comme ci-dessus, jusqu'à ce que le tableau soit vide :)

Re: Frise chronologique & CSS

Posté : 20 juil. 2016, 14:53
par finipe
Merci pour la réponse Ryle, j'ai pas eu le temps de la lire que j'avais choisi une autre solution :wink:

Ça donne ceci :
echo "<div id='FRISE'>";

// -- CADRE CHRONOLOGIQUE
echo "<div id='CHRONO_SIECLES'>";
for($i=1400 ; $i<=2000 ; $i+=100) echo "<p>".$i."</p>";
echo "</div>";

// Origine de la frise : 1400
$ORIGINE = 1400;

// Variable de définition du niveau d'affichage du compositeur
// cle : niveau d'affichage
// valeur : date de fin du niveau (à partir de laquelle on peut mettre un compositeur sur ce même niveau)
$NIVEAU = array(1 => $ORIGINE);

// -- AFFICHAGE DES COMPOSITEURS DEPUIS LA BASE
for($i=1 ; $i<=7 ; $i++)
{
	$result = mysqli_query($DB, "SELECT * FROM compositeurs WHERE periode='".$i."' ORDER BY naissance ASC");
	while($row = mysqli_fetch_array($result))
	{
		// Naissance et mort du compositeur
		// --> Si le compositeur n'est pas mort, la fin de la barre correspond à l'année en cours
		if(empty($row['mort']))	$fin = date(Y);
		else					$fin = intval($row['mort']);
		$debut = intval($row['naissance']);

		// Durée de vie
		$longevite = $fin - $debut;

		// Définition du niveau d'affichage
		$N = FALSE;
		for($k=1 ; $k<=sizeof($NIVEAU) ; $k++)
		{
			// Si les compositeurs ne se chevauchent pas, on sélectionne ce niveau d'affichage
			// et on met la valeur à jour
			if($debut >= $NIVEAU[$k])
			{
				// Définition marge gauche (Echelle : pixels/année = 4)
				$marge_L = ($debut-$ORIGINE)*4;

				// Mise à jour du niveau sélectionné
				$NIVEAU[$k] = $fin;
				$N = $k;
				break;
			}
		}

		// Si aucun niveau n'a pu être sélectionné, on en crée un nouveau
		if($N == FALSE)
		{
			// Définition marge gauche (Echelle : pixels/année = 4)
			$marge_L = ($debut-$ORIGINE)*4;

			// Définition du nouveau niveau
			$NIVEAU[] = $fin;
			$N = sizeof($NIVEAU);
		}

		// Définition marge haute (hauteur compositeur = 36px, +2px d'espace +50px de marge haute incompressible)
		$marge_T = ($N-1)*38 + 50;
		echo "<div class='CHRONO_COMPO' style='top:".$marge_T."px; left:".$marge_L."px; color:".$__PERIODE[intval($row['periode'])][2]."; background-color:".$__PERIODE[intval($row['periode'])][1]."; width:".($longevite*4)."px;'>".$row['prenom']." ".$row['nom']."<br />".$row['naissance']."-".$row['mort']."</div>";
	}
}

echo "</div>"; // Fin #FRISE
Et le CSS :

Code : Tout sélectionner

html, body { margin:0; } #FRISE { overflow:auto; height:500px; width:2800px; margin:0; font-family:Georgia, serif; background:#EFEFEF url(Images/fond_frise.png); } #CHRONO_SIECLES { width:2800px; z-index:-1; } #CHRONO_SIECLES p { font-size:1.5em; margin:0 0 20px 0; padding-left:2px; width:398px; display:inline-block; } .CHRONO_COMPO { display:block; position:absolute; cursor:pointer; text-align:center; font-size:0.7em; height:36px; display:block; color:black; line-height:18px; } .CHRONO_COMPO:hover { box-shadow:0px 0px 0px 2px #000000 inset; }

Et le résultat :
Image

Mon seul problème, c'est qu'avec la position absolute, mon conteneur principal #FRISE n'ajuste pas sa hauteur avec ce qu'il contient... Y a un truc CSS miracle pour faire ça sans être obligé de calculer en php la hauteur du conteneur ? Parce que sinon, faut que je revoie mon algo :?

Re: Frise chronologique & CSS

Posté : 20 juil. 2016, 15:27
par finipe
Pardon, j'ai pas réfléchi, c'était simple : au lieu d'afficher immédiatement les compositeurs avec "echo", j'ai stocké le tout dans une chaîne de caractère, puis j'ai calculé la hauteur de mon div #FRISE en fonction du niveau atteint, et enfin j'ai tout affiché.

Bref, sujet résolu, merci pour votre aide :)