CSS3-Lauftexte mit RSS (Teil 2)

Im letzten Artikel unseres Workshops Digital Signage Newsticker haben wir die erste Basistechnologie für horizontale Lauftexte kennengelernt. Sie basiert auf CSS3-Animationen. In diesem Beitrag werden wir eine richtige Digital Signage Anwendung entwickeln, in dem wir dynamisch Informationen aus einem RSS-Feed hinzufügen.
Wir gehen davon aus, daß Sie bereits wissen, was ein RSS-Feed ist. Ansonsten klicken Sie auf diesen Beitrag. Dort werden Feeds und RSS ausführlicher erklärt.

Das nächste Level

Im letzten Beispiel erstellten wir einen einfachen Lauftext zur Veranschaulichung. Der Digital Signage Alltag stellt uns aber vor größere Herausforderungen. Wenn der Text aus einem RSS-Feed kommt, ist die Textlänge variabel. Es ist auch unbekannt welche horizontale Auflösung das Endgerät besitzt. Deshalb müssen wir das Design flexibel gestalten. Darüber hinaus bekommen wir nun ein Problem mit der Sicherheitspolitik der Webbrowser. Die sogenannte SOP (Same-Origin-Policy) erlaubt es nicht, per Javascript oder CSS Inhalte von einer anderen Domain als die gerade eigene aufzurufen. Diese Hürden werden wir eine nach der anderen nehmen.

Ein flexibleres Design für das Konzept CSS3-Lauftexte mit RSS

Sie erinnern sich an css3_animations_2.html? Die CSS3-Lauftexte mit RSS sollen jetzt über die komplette Breite der Seite gehen. D.h. Wir verändern den Style-Bereich und HTML-Code zu folgendem:

<style>
	#ticker
	{
		position: relative;
		font: 30px Arial;
		white-space: nowrap;
		animation: moveTicker 10s linear infinite;
		display: inline-block;	
		
	}
	@keyframes moveTicker
	{
		from
		{
			transform: translate3d(0%, 0%, 0px);
			left: 100%;
		}
		to
		{
			transform: translate3d(-100%, 0%, 0px);
			left: 0%;
		}
	}		
</style>

und den Body-Bereich zu:

<body onload="start()">
	<div id="ticker"></div>
</body>

Ein Wrapper-div ist jetzt unnötig geworden und wurde gelöscht. Da das Ticker-div seinen Text aus dem späteren Javascript bekommen soll, bleibt es zunächst leer. Das onload-Ereignis im body-Tag erklären wir weiter unten.
In dem Stylesheet für den Ticker gibt es ein paar Änderungen. Die Animationsdauer wird später in Abhängigkeit von der Anzahl der Überschriften gesetzt und ist hier irrelevant.
Wie eingangs erwähnt, wissen wir nicht welche horizontale Auflösung das zukünftige Anzeigegerät hat. Ohne die neuen Änderungen würde das Ticker-div auf die Breite des Browserfenster gesetzt werden. Diese ist in der Regel viel kleiner, als die Breite des eigentlichen Textes. D.h. der Lauftext läuft nie komplett durch, weil er mittendrin immer wieder auf den Startpunkt zurückspringt und von neuem anfängt.
Damit das nicht passiert, wird das Element als inline-block gesetzt. Somit können zwar horizontale Positionierungen genutzt (analog display:block) werden, aber das Element verhält sich wie z.B. ein span-Element. Diese Elemente haben keinen Zeilensprung, keine festlegbare Breite und können daher mit anderen Inline-Elementen in der gleichen Zeile stehen. Das ist wichtig damit der Trick mit der Kombination einer Positionsangabe (left) und der Transformation (translate3d) funktionieren kann.

Transformationen mit Positionsangabe

Positionsangaben und Transformationen verhalten sich unterschiedlich. Die Angabe „left“ bezieht sich auf das Elternelement, „translate“ aber auf das Element selbst. Bei den von uns benötigten Prozentangaben fällt das besonders ins Gewicht.
Ein Beispiel: Wenn wir bei from-Bereich ein scheinbar zu „left:100%“ identisches transform: translate3d(100%, 0%, 0px) setzen würden, startet der Text viel zu weit rechts im Off. Bei jedem „herauslaufen“ links dauert es lange, bis der Text rechts wieder beginnt. Die 100% des Tickerelement sind absolut (in Pixel) gesehen größer, als die 100% des Browserfensters. Durch left:100% und translate3d(0%, 0%, 0px) stellen wir sicher, dass der Startpunkt genau auf Position 100% der Browserfensterbreite steht. Das reicht aber noch nicht aus. Der Text läuft jetzt nämlich wie oben beschrieben nicht komplett durch, sondern startet zu früh wieder von vorn. Wir müssen also zusätzlich die Endposition explizit als left:0% mit -100% transformation deklarieren, um einen kompletten Durchgang zu gewährleisten.

Ereignisse im Body-Tag

Um die Javascript-Verarbeitung erst zu starten nachdem der HTML-Teil komplett geladen ist, nutzen wir im body-Tag das Ereignis onLoad. Dieses Ereignis ruft die Funktion start() auf, welche einen Prozess in Gang setzt, den wir im Folgenden genauer beschreiben werden.

Der Javascript-Algorithmus

Wir konstruieren an Anfang einen Algorithmus, der aus vier Schritten besteht.

  1. Das RSS als JSON-Text abholen
  2. Das erhaltene JSON in ein Javascript-Objekt konvertieren
  3. Aus dem Javascript-Objekt den Text für den Ticker extrahieren
  4. Den Tickertext ausgeben

JSON (JavaScript Object Notation) ist übrigens ein Standardformat in Textform, um strukturierte Daten unkompliziert austauschen zu können.

SOP umgehen

Für die Beispiele benutzen wir unseren eigenen RSS-Feed auf https://smil-control.de/blog/feed/. Um diesen abzufragen, ohne mit dem oben erwähnten Browsersicherheitskonzept (Same Origin Police) in Konflikt zu geraten, gibt es mehrere Lösungen. Z.B. CORS (Cross-Origin Resource Sharing), JSONP oder gar ein eigenes serverseitiges Skript. Allerdings besitzen diese Lösungen ihre Vor- und Nachteile und erfordern Zusatzarbeiten deren Erläuterungen den Rahmen dieses Tutorials sprengen würden. Daher haben wir uns für den Einsatz der Yahoo Query Language (YQL) entschieden. Unter https://developer.yahoo.com/yql/ stellt Yahoo diese Schnittstelle der Allgemeinheit frei zur Verfügung. Mit z.B. ’select title, description from rss where url=“https://smil-control.de/blog/feed“&format=json‘ bekommen wir alle title- und description-Tags des Feeds im JSON-Format zurück.

Das RSS als JSON-Text abholen

Die Funktion getRSS wird mit der Url des RSS Feeds aufgerufen und sieht so aus:

function getRSS(url)
{
	var request_url = 'https://query.yahooapis.com/v1/public/yql?q=select title from rss where url="'+url+'"&format=json';
	var MyRequest = new XMLHttpRequest();
	MyRequest.open("GET", request_url, true);
	MyRequest.onload = function (e)
	{
		if (MyRequest.readyState === 4)
		{
			if (MyRequest.status === 200)
			{
				handleTicker(MyRequest.responseText);
			}
			else
			{
				console.error(MyRequest.statusText);
			}
		}
	};
	MyRequest.onerror = function (e)
	{
		console.error(MyRequest.statusText);
	};
	MyRequest.send(null);
}

Als erstes wird die Abfrage-Url zusammengestellt. Da für die Laufleiste nur der Title als Headline relevant ist fordern wir auch nur den an. Mit new XMLHttpRequest() wird ein neues Objekt (hier: MyRequest) für eine Datenabfrage über eine Url angelegt. Durch die Funktion open() wird eine GET-Afrage asynchron initialisiert und schliesslich mit send() abgeschickt. GET stellt eine einfache HTTP-Anfrage dar, um Daten von einem Server anzufordern. Im Prinzip als ob Sie etwas in die Adresszeile Ihres Browsers eingeben. Asynchron bedeutet, dass nach dem Senden der Abfrage das Skript nicht auf die Antwort wartet, um fortzufahren. Das sind die in modernen Webanwendungen üblichen sogenannten AJAX-Abfragen. Asynchrone Abfragen werden im Hintergrund ausgeführt und blockieren der Browser nicht. Der kann dann mit anderen Dingen fortfahren z.B. dem Bildaufbau.

Eventhandler

Des Weiteren erstellen wir zwei sogenannte Eventhandlerfunktionen. Onerror wird aktiviert, wenn es einen Fehler gibt z.B. die Yahoo-Url nicht erreichbar ist. Sollte der Fall eintreten schreiben wir die Fehlermeldung in die Konsole. In der Funktion onload wird geprüft ob ein Ergebnis vorliegt. D.h die readyState-Eigenschaft der Abfrage den Wert 4 einnimmt. Als nächstes wird der sogenannte Statuscode der Antwort von Yahoo überprüft. Wenn alles in Ordnung ist, steht der Statuscode auf 200 und das Skript übergibt den Text der Antwort an die Funktion handleTicker() zum Weiterverarbeiten. Andernfalls wird eine Fehlermeldung in der Konsole ausgegeben.
Die Funktion handleEvent übernimmt nun im Erfolgsfall die weiteren Schritte des oben ermittelten Algorithmus.

function handleTicker(response)
{
	var feed_obj    = JSON.parse(response);
	var ticker_text = createTickerOutput(feed_obj);
	displayTicker(ticker_text, feed_obj.query.count);			
}

JSON zu Javascriptobjekt konvertieren

Der aus der Funktion getRSS() übergebenen Text im JSON-Format wird mit JSON.parse(response) in ein Javascript-Objekt umgewandelt. Achtung! In alten Tutorials ist eventuell von eval() die Rede, da JSON.parse erst Dezember 2009 als ECMA 5.1 Standard eingeführt wurde. Mit eval() lässt sich Javascript-Code ausführen und JSON in Objekte umwandeln. Versuchen Sie die Nutzung grundsätzlich zu vermeiden, weil diese auch das Risiko birgt, ungewollt eingeschleusten Schadcode zur Ausführung zu bringen. JSON.parse() ist sicherer und wird zudem schneller ausgeführt.

Extrahieren des Ticker-Textes aus dem Objekt

function createTickerOutput(feed_obj)
{
	var ticker_text = "";
	for (var i = 0; i < feed_obj.query.count; i++)
	{
		ticker_text += feed_obj.query.results.item[i].title+ " +++ ";
	}
	return ticker_text;
}

Die Funktion durchläuft mit der for-Schleife Schritt für Schritt alle Meldungen (items) des Feed-Objektes. Dabei wird das title-Feld für die Schlagzeile extrahiert und dem String ticker_text angefügt. In ticker_text befinden sich nach Beendigung der Schleife alle Schlagzeilen mit einem „+++“ getrennt. Diese Variable wird zurückgeliefert und bildet die Basis für den Lauftext.

Die Animationsdauer ermitteln

Die Dauer, in der eine Animation abläuft, muss im Stylesheet gesetzt werden. Eine feste Zeit birgt Probleme bei unterschiedlichen Textlängen. In 10s lassen sich 20 Überschriften, die ein Feed durchaus haben kann, sicherlich nicht bequem lesen. Ist die Zeit hingegen zu zu hoch, scrollt der Ticker quälend langsam. Abhilfe schafft eine Funktionalität die in Abhängigkeit zu der Anzahl der Überschriften die Animationsdauer ermittelt:

 
function getAnimDurationInSeconds(num)
{
	var seconds = num*10;
	return seconds.toString()+"s";
}

Um die Animationsdauer zu berechnen, setzen wir 10s Lesezeit pro Schlagzeile an. Bei 5 Schlagzeilen wären das 50 Sekunden. Gute Schlagzeilen bestehen in der Regel aus 4-8 Worten. Also sollten 10 Sekunden Zeit einen ruhigen Lauftext zu lesen näherungsweise angemessen sein. Sie können aber auch gerne mit diesem Faktor „herumspielen“, bis die Geschwindigkeit Ihren Wünschen entspricht.

Der Lohn der Mühen

Im letzte Schritt befüllen wir das Ticker-div mit dem oben extrahiertem Text und setzen die Animationszeit.

function displayTicker(ticker_text, num_headlines)
{
	var ticker                     = document.getElementById("ticker");
	ticker.innerHTML               = ticker_text;
	ticker.style.animationDuration = getAnimDurationInSeconds(num_headlines);
} 

Wir initialisieren erst eine Variable namens ticker, um das Ticker-div anzusprechen. Als nächstes bekommt das div den Inhaltstext und zum Schluss setzen wir im CSS die berechnete Animationszeit.
Klicken sie auf css_animation_rss.html, um die CSS3-Lauftexte mit RSS zu betrachten. Sie werden sehen, dass der Ticker sich immer gleich verhält. Sogar wenn Sie während des Ablaufes die Breite Ihres Browserfensters ändern.

Wie geht es weiter?

Im nächsten Beitrag werden wir einen horizontalen Lauftext basierend auf HTML5-Canvas erstellen und diesen ebenfalls aus einem RSS-Feed befüllen.
Wenn Sie Fragen oder Anmerkungen haben, können Sie uns gerne kontaktieren.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.