Kategorien
JavaScript & jQuery Programmierung Webdesign

JavaScript: Template-String erlaubt Variablen und Umbrüche in Zeichenketten

Arbeitet man mit JavaScript, kommt es immer wieder vor, dass Variablen oder Zeilenumbrüche  in einer Zeichenkette untergebracht werden müssen. Während man Variablen per Plus-Zeichen an eine Zeichenkette anhängt, ist das Einfügen von Zeilenumbrüchen nur als spezielle Steuerzeichen vorgesehen. Mit den neuen Template-String-Möglichkeiten von JavaScript, die derzeit noch experimentell sind, lassen sich Variablen und Umbrüche künftig deutlich unkomplizierter in einer Zeichenkette unterbringen.

javascript-templatestring-teaser_DE

Template-String auszeichnen

Die neuen Template-Strings erkennt man daran, dass sie anders als herkömmliche Zeichenketten nicht in Anführungszeichen stehen, sondern von sogenannten Backticks – ` – umschlossen sind. Es handelt sich hierbei um das Akut-Zeichen, welches vor allem im Französischen als „accent grave“ Verwendung findet. JavaScript erkennt Zeichenketten, die in Backticks stehen, als Template-Strings und interpretiert ihren Inhalt anders als einfache Zeichenketten.

var string = "Dies ist eine einfache Zeichenkette";
var templatestring = `Dies ist ein Template-String.`;

Will man beispielsweise Variablen in einer Zeichenkette unterbringen, ist dies per Template-Strings möglich, ohne die Zeichenkette für die Variable unterbrechen zu müssen. Variablen können quasi als Platzhalter in einen Template-String integriert werden.

var zahl1 = 10;
var zahl2 = 15;

var string = "Addiert man " + zahl1 + " mit " + zahl2 + ", ergibt das " + (zahl1 + zahl2) + ".";

var templatestring = `Addiert man ${zahl1} mit ${zahl2}, ergibt das ${zahl1 + zahl2}.`;

Das Beispiel zeigt, dass man sich bei Template-Strings die wiederkeherenden Anführungs- und Pluszeichen schenken kann und somit auf eine insgesamt kürzere Zeichenkette kommt. Das ist übersichtlicher und vor allem weniger anfällig für Fehler. Denn gerade fehlende Anführungszeichen sind eine häufige Fehlerquelle bei der Programmierung. Damit Variablen in Template-Strings zu erkennen sind, müssen sie in geschwungenen Klammern stehen und mit einem Dollar-Zeichen eingeleitet werden („${…}“).

Das Einfügen von Variablen in eine Zeichenkette, wie es die Template-Strings ermöglichen, gibt es auch bei anderen Programmiersprachen. So existiert eine ähnliche Auszeichnung von Variablen auch in PHP, wenngleich die Trennung von Zeichenkette und Variable in der Regel etwas performanter ist.

Template-String als Array ausgeben

Eine weitere Besonderheit der Template-Strings ist die Möglichkeit, Inhalt als Array auszugeben. Übergibt man einen Template-String an eine Funktion, lassen sich die einzelnen per Leerzeichen getrennten Zeichenketten separat auslesen.

function zerlegen(zeichenkette, wert1, wert2, wert3) {
  console.log(zeichenkette[0]); // "Addiert "
  console.log(wert1); // "10"
  console.log(wert2); // "15";
}
zerlegen `Addiert man ${zahl1} mit ${zahl2}, ergibt das ${zahl1 + zahl2}.`;

Im Beispiel wird die Funktion „zerlegen()“ erstellt, der vier Argumente übergeben werden können. Übergibt man dieser Funktion einen Template-String, werden alle Textbestandteile dem Array „zeichenkette“ zugewiesen. Der variable Inhalt, der per „${…}“ gekennzeichnet ist, wird den Variablen „wert1“, „wert2“ und „wert3“ zugeordnet.

Anders als bei der klassischen „split()“-Methode bleiben die Leerzeichen erhalten. Wichtig ist, dass beim Funktionsaufruf – anders als üblich – der Template-String nicht in Klammern stehen darf.

Zeilenumbrüche in Template-String

Will man in einer normalen Zeichenkette einen Zeilenumbruch unterbringen, muss man diesen mit dem Steuerzeichen „\n“ auszeichnen. In Template-Strings kann auf dieses Steuerzeichen verzichtet werden. Stattdessen reicht ein tatsächlicher Zeilenumbruch aus.

var string= "Zeile 1\nZeile 2";

var templatestring = `Zeile 1
Zeile 2`;

Würde man in einer normalen Zeichenkette einen tatsächlichen Zeilenumbruch unterbringen, würde dies zu einer Fehlermeldung führen. Allerdings ist es auch möglich, innerhalb von Template-Strings Steuerzeichen einzusetzen. Mit der Methode „String.raw()“ gibt man zudem etwaige Steuerzeichen in einem Template-String als solche aus.

console.log(`Zeile 1\nZeile 2`);

console.log(String.raw `Zeile1\nZeile2`);

Im zweiten Beispiel wandeln wir das Steuerzeichen nicht um, sondern geben es als „\n“ aus. Wie auch bei Funktionen, darf der Template-String nicht in Klammern an die Methode übergeben werden.

Browsersupport

Derzeit werden Template-Strings nur vom aktuellen Firefox ab der Version 34 und Chrome ab der Version 41 unterstützt. Template-Strings bereichern JavaScript nicht mit neuen Funktionen, können aber für übersichtlicheren und weniger fehleranfälligen Quelltext sorgen.

Kategorien
JavaScript & jQuery Programmierung Sonstige Programmiersprachen

ECMAScript 6 besser verstehen: Klassen und Vererbung

Hiermit möchte ich Sie zu einer Serie von Artikeln über ECMAScript 6 einladen, mit der ich nicht nur meine Begeisterung darüber teilen, sondern vor allem erklären will, wie man ECMAScript 6 am besten verwenden kann. Ich hoffe, Sie haben mindestens soviel Spaß beim Lesen, wie ich beim Schreiben hatte.

ecmascript01-teaser_DE

Zu meinem Hintergrund: Ich arbeite bei Microsoft an der Browser Rendering Engine für das Microsoft Edge, welche gegenüber der bisherigen Internet Explorer Engine, die wir im Lauf der Jahre ausgiebig kennen (und lieben?) gelernt haben, ein gewaltiger Schritt nach vorn ist. Mein persönliches Lieblings-Feature dabei ist, dass sie jede Menge ECMAScript 6 unterstützt. Das erleichtert das Schreiben von komplexen Web-Applikationen ungemein.

Laut http://kangax.github.io/compat-table/es6/ und ES6 on dev.modern.ie/platform/status haben wir derzeit fast 70% der ECMAScript 6 Features in Microsoft Edge.

Keine Frage, ich mag es mit JavaScript zu arbeiten, aber wenn ich an großen Projekten wie Babylon.js sitze, greife ich lieber auf TypeScript zurück, das jetzt auch Angular 2 antreibt. Der Grund ist, dass ich bei JavaScript (auch bekannt als ECMAScript 5) einige Syntax-Funktionen vermisse, die andere Programmiersprachen, mit denen ich große Projekte schreibe, mitbringen. Zum Beispiel fehlen mir Klassen und Vererbungen.

Wie Sie von JavaScript auf TypeScript umsteigen, erfahren Sie in diesem Artikel. Eine ausführliche Einführung in TypeScript erhalten Sie in diesem kostenlosen Online-Kurs der Microsoft Virtual Academy (MVA). Den kostenlosen Download zu TypeScript 1.4 für Visual Studio 2013 finden Sie hier.

Eine Klasse erstellen

JavaScript ist eine prototypen-basierte Sprache und mit ECMAScript 5 kann man Klassen und Vererbungen simulieren. Sie möchten die Performance Ihrer Webanwendung verbessern? Hier finden Sie praktische Tipps zur Verbesserung Ihres HTML/JavaScript Codes.

Die flexiblen Funktionen von JavaScript erlauben uns, eine Datenkapselung zu simulieren, als ob wir mit Klassen arbeiten würden. Um dies zu erreichen, erweitern wir den Prototyp eines Objekts:

var Animal = (function () {
    function Animal(name) {
        this.name = name;
    }
    // Methods
    Animal.prototype.doSomething = function () {
        console.log("I'm a " + this.name);
    };
    return Animal;
})();


var lion = new Animal("Lion");
lion.doSomething();

Deutlich wird hier, dass wir eine „Klasse“ mit „Eigenschaften“ und „Methoden“ definiert haben.

Der Konstruktor ist dabei durch die Funktion selbst definiert (function Animal). Dies ermöglicht uns die Instanziierung von Eigenschaften. Durch die Nutzung des Prototyps können wir Funktionen definieren, die wie Instanzmethoden behandelt werden.

Man kann es also durchaus so machen, muss aber Einiges von prototypischer Vererbung verstehen. Und wer an klassenbasierte Sprachen gewöhnt ist, findet das sicher alles etwas verwirrend. Etwas seltsam ist natürlich auch, dass in JavaScript zwar das Schlüsselwort Klasse existiert, es aber nichts bewirkt. ECMAScript 6 hingegen bringt dieses jetzt zum Laufen, und das Ganze auch noch mit einem einfacheren Code:

class AnimalES6 {
    constructor(name) {
        this.name = name;
    }

    doSomething() {
        console.log("I'm a " + this.name);
    }
}

var lionES6 = new AnimalES6("Lion");
lionES6.doSomething();

Am Ende haben wir das gleiche Ergebnis. Aber für Entwickler, die gewohnt sind, mit Klassen zu arbeiten, ist das Ganze weitaus leichter zu schreiben und zu lesen. Ein Prototyp ist dazu hier nicht nötig und und man nutzt einfach das Keyword „Constructor“ um den Konstruktor zu definieren.

Darüber hinaus bringen Klassen viel neue Semantik mit, die in ECMAScript 5 nicht vorhanden war. So kann ein Konstruktor nicht ohne das Keyword „new“ aufgerufen oder Methoden mit „new“ konstruiert werden. Eine weitere Veränderung: Methoden sind nicht aufzählbar.

Interessant ist jedoch: Beide Versionen können parallel genutzt werden.

Denn trotz der neuen Keywords, am Ende des Tages landen wir bei einer Funktion mit einem Prototyp, dem eine Funktion hinzugefügt wurde. Eine „Methode“ bezeichnet hier einfach eine Funktionseigenschaft des Objekts.

Eine weitere Kernfunktion klassenbasierter Entwicklung, "getter and setter", wird ebenfalls von ES6 unterstützt. Dadurch wird schnell deutlich, was der Sinn von Methoden ist und was sie tun sollen:

class AnimalES6 {
    constructor(name) {
        this.name = name;
        this._age = 0;
    }

    get age() {
        return this._age;
    }

    set age(value) {
        if (value < 0) {
            console.log("We do not support undead animals");
        }

        this._age = value;
    }

    doSomething() {
        console.log("I'm a " + this.name);
    }
}

var lionES6 = new AnimalES6("Lion");
lionES6.doSomething();
lionES6.age = 5;

Ganz praktisch, oder?

Gleichzeitig kommt hier einer der typischen Vorbehalte gegenüber JavaScript zum Vorschein: der gar nicht so vertrauliche „private Member“ (_age). Mehr zu diesem Thema schrieb ich in diesem Artikel.

Mit einer neuen Funktion von ECMAScript 6 haben wir nun einen eleganteren Weg, dies umzusetzen und zwar mithilfe von „Symbolen“:

var ageSymbol = Symbol();

class AnimalES6 {
    constructor(name) {
        this.name = name;
        this[ageSymbol] = 0;
    }

    get age() {
        return this[ageSymbol];
    }

    set age(value) {
        if (value < 0) {
            console.log("We do not support undead animals");
        }

        this[ageSymbol] = value;
    }

    doSomething() {
        console.log("I'm a " + this.name);
    }
}

var lionES6 = new AnimalES6("Lion");
lionES6.doSomething();
lionES6.age = 5;

Was also ist ein Symbol in diesem Zusammenhang? Es ist ein einzigartiger, unveränderlicher Datentyp, der es ermöglicht, eindeutige Objekteigenschaften zu definieren. Ohne das Symbol besteht kein Zugang zu den Eigenschaften.

Die Folge ist ein „persönlicherer“ Zugriff auf die Member. Oder zumindest ist dieser Zugriff jetzt nicht mehr so einfach. Symbole helfen zwar bei der Einzigartigkeit von Namen, aber diese Einzigartigkeit allein garantiert noch keinen Datenschutz. Es bedeutet nur: Wenn ein Schlüssel nötig ist, der mit einem anderen nicht kollidieren darf, erzeugen Sie ein neues Symbol.

Dass auch hier noch niemand so ganz "privat" ist, liegt an Object.getOwnPropertySymbols. Damit können andere auf die Symboleigenschaften zugreifen.

Mit Vererbungen arbeiten

Sobald wir Klassen haben, erwarten wir auch Möglichkeiten der Vererbung. Auch hier war es bisher schon möglich, Vererbung in ES5 zu simulieren, aber es war schon eine recht komplexe Angelegenheit.

So sah es zum Beispiel aus, wenn TypeScript Vererbung nachbildete:

var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
var SwitchBooleanAction = (function (_super) {
     __extends(SwitchBooleanAction, _super);
     function SwitchBooleanAction(triggerOptions, target, propertyPath, condition) {
        _super.call(this, triggerOptions, condition);
        this.propertyPath = propertyPath;
        this._target = target;
     }
     SwitchBooleanAction.prototype.execute = function () {
        this._target[this._property] = !this._target[this._property];
     };
     return SwitchBooleanAction;
})(BABYLON.Action);

Nicht unbedingt sehr leicht zu lesen, oder? Die Alternative von ECMAScript 6 sieht da schon besser aus:

var legsCountSymbol = Symbol();
class InsectES6 extends AnimalES6 {
    constructor(name) {
        super(name);
        this[legsCountSymbol] = 0;
    }

    get legsCount() {
        return this[legsCountSymbol];
    }

    set legsCount(value) {
        if (value < 0) {
            console.log("We do not support nether or interstellar insects");
        }

        this[legsCountSymbol] = value;
    }

    doSomething() {
        super.doSomething();
        console.log("And I have " + this[legsCountSymbol] + " legs!");
    }
}

var spiderES6 = new InsectES6("Spider");
spiderES6.legsCount = 8;
spiderES6.doSomething();

Mithilfe des Keywords „extends“ lassen sich Klassen von einer anderen ableiten, also spezialisierte Klassen erzeugen („child“). Das Keyword „super“ stellt dann die Beziehung zur Basisklasse her.

Dank all dieser neuen Features können wir nun Klassen erzeugen und mit Vererbungen arbeiten, ohne uns Hilfe in Hogwarts holen zu müssen, um das Gleiche mit Prototypen zu erreichen.

Warum TypeScript noch relevanter ist als zuvor…

Nachdem wir nun die beschriebenen neuen Funktionen in unserem Browser haben, ist es meiner Meinung nach sogar noch sinnvoller als vorher, TypeScript zu nutzen, um JavaScript-Code zu erstellen.

Schließlich unterstützt TypeScript (1.4) jetzt ECMAScript 6 Code (mit let und const Keywords). Bereits existierender TypeScript-Code kann also weiter verwendet werden, man muss nur noch diese neue Option aktivieren, um ECMAScript 6 Code zu erstellen.

Und wer sich ein paar Zeilen TypeScript genauer anschaut, wird feststellen, dass sie aussehen wie ECMAScript 6 ohne die Typen. Wer heute TypeScript beherrscht, wird morgen also auch ECMAScript 6 schneller verstehen.

Daniel Meixner und Chris Heilmann sprechen in dieser Ausgabe des TechTalk ausführlich über die Neuerungen bei Edge, ECMAScript 2015 und TypeScript.

Fazit

Wer mit TypeScript arbeitet, kann die Funktionen in allen Browsern nutzen, der Code wird in ECMAScript 5 umgewandelt. Wer ECMAScript 6 direkt im Browser nutzen will, muss auf Windows 10 aktualisieren und dort die Rendering Engine von Microsoft Edge testen. Wem das jedoch zuviel Aufwand ist, weil er nur mal eben die neuen Browser-Funktionen ansehen will: remote.modern.ie bietet den Zugriff auf einen Windows 10 Computer mit Microsoft Edge. Das klappt auch mit MacOS oder Linux-Maschinen.

Klar, Microsoft Edge ist nicht der einzige Browser, der den offenen Standard ES6 unterstützt. Wie weit der Support anderer Browser inzwischen reicht, ist hier verzeichnet: http://kangax.github.io/compat-table/es6/

Und um noch einmal euphorisch zu werden: Ich denke die Zukunftsaussichten für JavaScript mit ECMAScript 6 sind wirklich glänzend und ich kann es kaum erwarten, dass es von möglichst vielen Browsern unterstützt wird.

Dieser Artikel ist Teil der Web Dev Tech Series von Microsoft. Wir freuen uns, Microsoft Edge und seine neue EdgeHTML Rendering Engine mit Ihnen zu teilen. Kostenlose Virtual Machines oder Remote Testings für Mac, iOS, Android oder Windows gibt es hier: dev.modern.IE.

Kategorien
JavaScript & jQuery Programmierung

WebDev für Fortgeschrittene: Mit Oimo.js eine coole WebGL Babylon.js Demo bauen und dabei Kollisionen & Physik verstehen lernen

Heute steigen wir in die Grundlagen von Kollisionen, Physik & Collider ein. Dafür spielen wir ein wenig mit der WebGL-basierenden Engine babylon.js und nutzen begleitend dazu die Physik-Engine namens oimo.js.

oimobabylonteaser_DE

So sieht die Demo aus, die wir gemeinsam bauen werden: Babylon.js Espilit Physik Demo mit Oimo.js. Cool, oder?

Die Demo läuft in allen WebGL-kompatiblen Browsern, wie IE11, Firefox, Chrome, Opera Safari 8 oder wahlweise unter Nutzung von Microsoft Edge in Windows 10 Technical Preview. Innerhalb der Demo kann man sich wie in einem Ego-Shooter-Spiel bewegen. Drücken Sie die „s„-Taste, um ein paar Kugeln in die Szenerie zu werfen und die b„-Taste, um ein paar Kisten fliegen zu lassen. Mit der linken Maustaste kann man die Objekte zudem in Bewegung setzen.

Kollisionen verstehen

Im Wikipedia-Eintrag zum Thema Kollisionserkennung kann man unter anderem Folgendes lesen:

„Als Kollisionserkennung oder Kollisionsabfrage wird in der Algorithmischen Geometrie das Erkennen des Berührens oder Überlappens zweier oder mehrerer geometrischer (starrer oder deformierbarer) Objekte im zwei- oder dreidimensionalen Raum verstanden. Einer Kollisionserkennung folgt die Kollisionsantwort oder Kollisionsbehandlung, wodurch eine Reaktion auf die Kollision eingeleitet wird. Kollisionserkennungsmethoden werden beispielsweise bei der Bildgenerierung von Animationsfilmen, in physikalischen Simulationen, bei Computerspielen, zur Pfadplanung in der Robotik oder bei Haptics eingesetzt. (…) Das Erkennen einer Kollision löst die Kollisionsantwort aus (siehe auch Physik-Engine, Ragdoll-Engine). (…) Eine exakte Kollisionserkennung kann sehr hohen Rechenaufwand verursachen, weshalb bei einer großer Anzahl von Objekten auf effiziente approximative Algorithmen zurückgegriffen werden muss.

Die Wikipedia-Definition hebt außerdem hervor, dass Systeme zur Kollisionserkennung auch Zeitpunkt und Dauer eines Aufpralls und mehrfache Kontaktpunkte berechnen können. Zudem seien für die Lösung von Aufgaben der Kollisionserkennung vielfältige Konzepte aus der linearen Algebra und der Algorithmischen Geometrie erforderlich.

Jetzt wird es aber Zeit, die graue Theorie zu verlassen und in eine coole 3D-Landschaft einzutauchen, die unser Ausgangspunkt für dieses Tutorial ist.

In diesem tollen Museum kann man sich wie in der realen Welt bewegen. Keiner fällt durch den Fußboden, niemand läuft durch die Wände oder fliegt durch den Raum. Wir simulieren Schwerkraft. Das alles erscheint einleuchtend und normal, erfordert aber eine Menge Rechenleistung, um es in einer virtuellen 3D-Welt abzubilden. Wenn wir über Kollisionserkennung nachdenken, sollten wir zunächst die Frage klären, wie komplex diese sein soll. Man benötigt schon eine anständige Prozessorleistung, um zu prüfen, ob zwei Objekte oder Strukturen aufeinanderprallen. Das gilt umso mehr für eine JavaScript-Engine, bei der es eine komplexe Aufgabe ist, dies außerhalb des UI Thread umzusetzen.

Um besser zu verstehen, wie wir diese Komplexität in den Griff bekommen, bewegen wir uns innerhalb des Espilit-Museums in die Nähe des Schreibtisches:

Am Tisch kommt man einfach nicht vorbei, obwohl auf der rechten Seite anscheinend Platz genug ist. Ist unser Kollisionsalgorithmus fehlerhaft? Nein. (Babylon.js hat natürlich keine Bugs! ;-) ) Der Grund ist vielmehr, dass Michel Rousseau, der 3D-Künstler, der diese Szenerie erschuf, das genau so wollte. Für die Vereinfachung der Kollisionserkennung nutzte er hier einen speziellen „Collider“.

Was ist ein Collider?

Statt die Kollisionen mit den vollständigen Objektstrukturen zu testen, werden die Objekte in einfache, unsichtbare Geometrien verpackt. Diese Collider stehen vereinfachend für die Gesamtstruktur und werden von der Kollisions-Engine zur Berechnung genutzt. Meistens wird man kaum einen Unterschied bemerken und es spart jede Menge Prozessorleistung, da die dahinter liegende Mathematik viel weniger komplex ist.

Jede Engine unterstützt mindestens zwei Arten von Collider: den Quader oder Würfel und die Kugel. Dieses Bild zeigt es sehr deutlich:


Quelle: Computer Visualization, Ray Tracing, Video Games, Replacement of Bounding Boxes

Diese Ente gilt es darzustellen, aber statt mögliche Kollisionen aus allen erdenklichen Winkeln zu berechnen, können wir sie in den bestmöglichen Collider verpacken. In diesem Fall scheint ein Quader besser geeignet zu sein als eine Kugel, das hängt aber letztlich von der Gitterstruktur des einzelnen Objekts ab.

Nun zurück zur Espilit-Szenerie, in der nun die unsichtbare Geometrie hier halb-transparent in Rot dargestellt ist:

Jetzt wird klar, warum man an diesem Tisch nicht rechts vorbei kann: Man stößt mit diesem Quader zusammen (oder zumindest die Babylon.js-Kamera tut es). Es wäre jedoch kein Problem, die Breite des Quaders auf die Breite des Tisches zu verkleinern.

Übrigens: Wer Lust hat Babylon.js ernsthaft zu erlernen, kann unseren kostenlosen Kurs an der Microsoft Virtual Academy (MVA) besuchen. So kann man zum Beispiel direkt in die „Introduction to WebGL 3D with HTML5 and Babylon.js – Using Babylon.js for Beginners“ einsteigen. Auch der Code unserer interaktiven Spielwiese kann begutachtet werden: Babylon.js playground – Collisions sample.

Abhängig davon wie komplex die Kollisionen sind und welche Art von Physik-Engine verwendet wird, sind auch weitere Collider möglich: Kapseln und Gitternetze zum Beispiel.

Quelle: Getting Started with Unity – Colliders & UnityScript

Kapseln sind gut geeignet für die Darstellung von Menschen oder menschenähnlichen Figuren, da sie eher dieser Form entsprechen als ein Quader oder eine Kugel. Gitter werden in der Regel nie die vollständige Struktur abbilden, sondern nur eine vereinfachte Version, trotzdem sind sie weitaus genauer als Quader, Kugel oder Kapsel.

Die Startszene laden

Um die Espilit-Landschaft zu laden, gibt es zwei Möglichkeiten:

Option 1: Herunterladen von unserem GitHub Repository und dann im Modul „Introduction to WebGL 3D with HTML5 and Babylon.js – Loading Assets“ unseres MVA Kurses sehen, wie man eine .babylon Szene lädt. Prinzipiell muss man die Assets und die Babylon.js Engine auf einen Web Server spielen und die entsprechenden MIME-Typen für die .babylon Erweiterung festlegen.

Option 2: Herunterladen dieser vorgefertigten Visual Studio-Lösung. (.zip file).

Hinweis: Wer mit Visual Studio noch nicht so viel anzufangen weiß, dieser Artikel hilft weiter: Web developers, Visual Studio could be a great free tool to develop with. Übrigens: Die Pro-Version ist derzeit kostenlos für eine Reihe von Szenarien erhältlich. Sie heißt Visual Studio 2013 Community Edition.

Wer keine Lust hat, mit Visual Studio zu arbeiten, kann natürlich einfach weiter diesem Tutorial folgen. Hier kommt der Code, um die Szene zu laden. Wie gesagt, die meisten Browser unterstützen heutzutage WebGL, auch beim Mac lohnt es sich, die Kompatibilität mit dem Internet Explorer zu testen.

/// 
var engine;
var canvas;
var scene;
document.addEventListener("DOMContentLoaded", startGame, false);
function startGame() {
    if (BABYLON.Engine.isSupported()) {
        canvas = document.getElementById("renderCanvas");
        engine = new BABYLON.Engine(canvas, true);
        BABYLON.SceneLoader.Load("Espilit/", "Espilit.babylon", engine, function (loadedScene) {
            scene = loadedScene;
   
            // Wait for textures and shaders to be ready
            scene.executeWhenReady(function () {
                // Attach camera to canvas inputs
                scene.activeCamera.attachControl(canvas);
                
                // Once the scene is loaded, just register a render loop to render it
                engine.runRenderLoop(function () {
                    scene.render();
                });
            });
        }, function (progress) {
            // To do: give progress feedback to user
        });
    }
}

Mithilfe dieses Tutorials kann man von der in Babylon.js eingebetteten Kollisions-Engine in jedem Fall profitieren. Zumal sich diese Engine von einer Physik-Engine unterscheidet. Die Kollisions-Engine ist hauptsächlich dafür da, dass die Kamera mit der Umgebung in der Szene interagiert. Man kann die Schwerkraft an der Kamera an- oder ausstellen und man kann die Option „checkCollision“ an der Kamera aktivieren bezüglich der verschiedenen Strukturen. Die Kollisions-Engine teilt auch mit, ob zwei Strukturen aufeinanderprallen. Und das ist schon alles (naja, eigentlich ist es ganz schön viel). Die Kollisions-Engine löst weder Aktionen, Stöße noch Impulse aus, falls zwei Babylon.js Objekte zusammenstoßen. Erst eine Physik-Engine bringt die Objekte in Bewegung.

Wir haben diese Physik mittels eines Plugins in Babylon.js integriert. Mehr Informationen dazu gibt es hier: Adding your own physics engine plugin to babylon.js. Wir unterstützen zwei Open Source Physik-Engines: cannon.js und oimo.js. Oimo ist jetzt die bevorzugte, voreingestellte Physik-Engine.

Wer oben Option 1 gewählt hat, um die Szenerie zu laden, muss jetzt von unserem GitHub Oimo.js herunterladen. Es gibt dort die aktualisierte Version, die Babylon.js noch besser unterstützt. Wer Option 2 gewählt hat, findet in der VS-Lösung die bereits referenzierte Fassung im Scripts-Ordner.

Physik-Unterstützung aktivieren & Collider in physikalische Simulationen umwandeln

Als Erstes sollte man die Physik in der Szene aktivieren. Dazu einfach diesen Code einfügen:

scene.enablePhysics(new BABYLON.Vector3(0, -10, 0), new BABYLON.OimoJSPlugin());
//scene.enablePhysics(new BABYLON.Vector3(0, -10, 0), new BABYLON.CannonJSPlugin());

Man legt damit den Grad der Schwerkraft fest (-10 auf der Y-Achse in diesem Beispiel-Code, was ungefähr der Realität auf der Erde entspricht) und bestimmt die Physik-Engine, die genutzt werden soll. Wir greifen auf Oimo.js zurück, aber die kommentierte Zeile zeigt, wie man auch cannon.js einbinden kann.

Jetzt wiederholen wir das für alle nicht sichtbaren Collider, welche die Kollisions-Engine verwendet und aktivieren entsprechend die physikalischen Eigenschaften. Dafür einfach alle Strukturen suchen, bei denen „checkCollisions“ auf „true“ gesetzt sind, die aber in der Szene nicht sichtbar sind:

for (var i = 1; i < scene.meshes.length; i++) {
    if (scene.meshes[i].checkCollisions && scene.meshes[i].isVisible === false) {
        scene.meshes[i].setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor, { mass: 0, 
                                        friction: 0.5, restitution: 0.7 });
        meshesColliderList.push(scene.meshes[i]);
    }
}

Bitte auch die meshesColliderList angeben:

var meshesColliderList = [];

Und das war es auch schon! Jetzt aber schnell ein paar Objekte in den Raum werfen und ein bisschen Chaos in dieses schöne – aber doch etwas sehr aufgeräumte – Museum bringen.

Kugeln & Quader mit physikalischen Zuständen erzeugen

Jetzt gehen wir daran, der Szene einige Kugeln (mit einer Amiga-Textur) und Kisten (also Quader, hier mit einer Holzstruktur) hinzuzufügen. Die physikalischen Eigenschaften dieser Strukturen sind festgelegt. Das heißt zum Beispiel, dass sie abprallen, wenn sie in die Luft geworfen werden und dann auf den Boden treffen oder voneinander wegspringen, wenn zwei Objekte miteinander kollidieren. Die Physik-Engine muss dafür wissen, welche Collider für die Strukturen angewendet werden sollen (Fläche, Kugel oder Quader), welche Masse und Reibung sie besitzen.

Für die Option 1 kann man hier zwei Texturen herunterladen: physicsassets.zip

Zudem muss dieser Code dem Projekt hinzugefügt werden:

function CreateMaterials() {
    materialAmiga = new BABYLON.StandardMaterial("amiga", scene);
    materialAmiga.diffuseTexture = new BABYLON.Texture("assets/amiga.jpg", scene);
    materialAmiga.emissiveColor = new BABYLON.Color3(0.5, 0.5, 0.5);
    materialAmiga.diffuseTexture.uScale = 5;
    materialAmiga.diffuseTexture.vScale = 5;
    materialWood = new BABYLON.StandardMaterial("wood", scene);
    materialWood.diffuseTexture = new BABYLON.Texture("assets/wood.jpg", scene);
    materialWood.emissiveColor = new BABYLON.Color3(0.5, 0.5, 0.5);
}
function addListeners() {
    window.addEventListener("keydown", function (evt) {
        // s for sphere
        if (evt.keyCode == 83) {
            for (var index = 0; index < 25; index++) {
                var sphere = BABYLON.Mesh.CreateSphere("Sphere0", 10, 0.5, scene);
                sphere.material = materialAmiga;
                sphere.position = new BABYLON.Vector3(0 + index / 10, 3, 5 + index / 10);
                sphere.setPhysicsState(BABYLON.PhysicsEngine.SphereImpostor, { mass: 1 });
            }
        }
        // b for box
        if (evt.keyCode == 66) {
            for (var index = 0; index < 10; index++) {
                var box0 = BABYLON.Mesh.CreateBox("Box0", 0.5, scene);
                box0.position = new BABYLON.Vector3(0 + index / 5, 3, 5 + index / 5);
                box0.material = materialWood;
                box0.setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor, { mass: 4 });
            }
        }
    });
}

Deutlich wird hier, dass die Kisten viermal schwerer als die Kugeln sind.

Tipp: Wer besser verstehen will, wie unterschiedliche Materialien in Babylon.js agieren, schaut am besten dieses Modul an: Introduction to WebGL 3D with HTML5 and Babylon.js – Understanding Materials and Inputs oder probiert es gleich selbst mit unserem Online-Muster aus: Babylon.js Playground – Materials sample

Diese zwei Zeilen Code werden dann nach der Zeile scene.enablePhysics eingefügt:

CreateMaterials();
addListeners();

Dann das Web-Projekt starten, in die Mitte unseres Museums gehen und die S- und B-Tasten der Tastatur drücken. Dieser Spaß sollte daraufhin zu sehen sein:

Auswahlfunktion den Strukturen hinzufügen

Auch ein cooles Feature: die Möglichkeit, auf ein Objekt zu klicken und es wegzuwerfen. Dafür muss ein Strahl von den 2D-Koordinaten der Maus innerhalb der Szene gesendet und überprüft werden, ob dieser Strahl eine bestimmte Struktur trifft, und wenn ja, muss dann ein Impuls ausgelöst werden, um das Objekt zu bewegen.

Tipp: Wer mehr dazu erfahren will, sieht sich am besten dieses MVA-Modul an: Introduction to WebGL 3D with HTML5 and Babylon.js – Advanced Features oder probiert es gleich selbst mit unserem Online-Beispiel aus: Babylon.js Playground – Picking sample.

Der folgende Code wird in die addListeners() Funktion eingefügt:

canvas.addEventListener("mousedown", function (evt) {
    var pickResult = scene.pick(evt.clientX, evt.clientY, function (mesh) {
        if (mesh.name.indexOf("Sphere0") !== -1 || mesh.name.indexOf("Box0") !== -1) {
            return true;
        }
        return false;
    });
    if (pickResult.hit) {
        var dir = pickResult.pickedPoint.subtract(scene.activeCamera.position);
        dir.normalize();
        pickResult.pickedMesh.applyImpulse(dir.scale(1), pickResult.pickedPoint);
    }
});

Dann den Code im bevorzugten Browser starten. Jetzt kann man auf die physikalischen Gitterstrukturen klicken und alles ausprobieren.

Collider anzeigen um das Ganze noch besser zu verstehen

Abschließend erstellen wir eine Debug Szene, die es uns ermöglicht, die Collider anzuzeigen oder zu verbergen, sowie die physikalischen Eigenschaften zu aktivieren/deaktivieren.

Dazu fügen wir die UI in diese div ein:

<div id="lcContainer"></div>

Außerdem nutzen wir diese Funktion, um die UI zu bearbeiten:

function CreateCollidersHTMLList() {
    var listColliders = document.getElementById("listColliders");
    for (var j = 0; j < meshesColliderList.length; j++) {
        var newLi = document.createElement("li");
        var chkVisibility = document.createElement('input');
        chkVisibility.type = "checkbox";
        chkVisibility.name = meshesColliderList[j].name;
        chkVisibility.id = "colvis" + j;
        var chkPhysics = document.createElement('input');
        chkPhysics.type = "checkbox";
        chkPhysics.name = meshesColliderList[j].name;
        chkPhysics.id = "colphysx" + j;
        (function (j) {
            chkVisibility.addEventListener(
             "click",
             function (event) {
                 onChangeVisibility(j, event);
             },
             false
           );
            chkPhysics.addEventListener(
            "click",
            function (event) {
                onChangePhysics(j, event);
            },
            false
            );
        })(j)
        newLi.textContent = meshesColliderList[j].name + " visibility/physx ";
        newLi.appendChild(chkVisibility);
        newLi.appendChild(chkPhysics);
        listColliders.appendChild(newLi);
    }
    function onChangeVisibility(id, event) {
        if (!meshesColliderList[id].isVisible) {
            meshesColliderList[id].isVisible = true;
            meshesColliderList[id].material.alpha = 0.75;
            meshesColliderList[id].material.ambientColor.r = 1;
        }
        else {
            meshesColliderList[id].isVisible = false;
        }
    }
    function onChangePhysics(id, event) {
        if (!meshesColliderList[id].checkCollisions) {
            meshesColliderList[id].checkCollisions = true;
            meshesColliderList[id].setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor, { mass: 0, 
                                                   friction: 0.5, restitution: 0.7 });
        }
        else {
            meshesColliderList[id].checkCollisions = false;
            meshesColliderList[id].setPhysicsState(BABYLON.PhysicsEngine.NoImpostor);
        }
    }
}

Okay, ich gebe es zu, die entstandene UI gewinnt keinen Schönheitswettbewerb. Aber ich war ehrlich gesagt zu faul, um darauf mehr Zeit zu verwenden. Wer will, kann es besser machen! :-P

Jetzt die neue Funktion aufrufen und das Web-Projekt starten. Dann zum Beispiel die Collider 12 & 17 anzeigen:

Mit dem zweiten Kontrollkästchen können zudem die physikalischen Eigenschaften aktiviert/deaktiviert werden. Wer sie zum Beispiel beim Collider 12 deaktiviert und die Kugeln losschickt, bei dem fliegen sie plötzlich durch die Wand. Im folgenden Screenshot ist das bei der rot umrandeten Kugel gut zu sehen:

Wer direkt im Browser dieses Debugging-Beispiel ein wenig austesten will, los geht´s: babylon.js Espilit Physics debug demo.

Sehr zu empfehlen ist auch diese fantastische Demo von Samuel Girardin, die ebenfalls Oimo.js benutzt, hier zusammen mit ein paar echt lustigen Charakterköpfen.

Wie Sie eine 3D-Szene auf einem Windows Phone 8.1 mit WebGL und Cordova erstellen, erfahren Sie in diesem Blogbeitrag des Microsoft Open Technologies Blog.

Ich hoffe, das Tutorial hat Spaß gemacht! Kommentare via meinem Twitter Account http://twitter.com/davrous sind sehr willkommen.

Dieser Artikel ist Teil der Web Dev Tech Series von Microsoft. Wir freuen uns, Microsoft Edge und seine neue EdgeHTML rendering engine mit euch zu teilen. Kostenlose Virtual Machines oder Remote Testings für Mac, iOS, Android oder Windows gibt es hier:dev.modern.IE.

(dpe)

Kategorien
Design Essentials Freebies, Tools und Templates HTML/CSS JavaScript & jQuery Programmierung Responsive Design UI/UX Webdesign

12 nützliche HTML5, CSS3 und JavaScript Tools für Webdesigner und Entwickler

Webdesigner und Entwickler sind stets auf der Suche nach Tools, die ihnen die Arbeit erleichtern oder angenehmer gestalten. Neue Ressourcen für die Entwicklung von Websites mit HTML5 und CSS3 werden dabei natürlich immer gerne gesehen. Immer mehr Designer und Entwickler setzen bei Ihrer täglichen Arbeit gezielt auf HTML5 und CSS3, was man nicht oft genug empfehlen kann. Heute haben wir eine Liste mit neuen und nützlichen Ressourcen für Sie erstellt, die sich genau diesem Thema widmet.

html5css3-12tools-teaser_DE

Tools für Webdesign und Webentwicklung

HTML5 macht das Webdesign einfacher und funktionsreicher in vielen Belangen. Es kann Ihnen dabei helfen, Apps und Websites mit mehr Funktionalität und Performance auszustatten und faszinierende Desktop-Anwendungen zu kreieren. Die von uns vorgestellten HTML5-, CSS3- und auch JavaScript-Tools sollen Ihnen bei einer schnellen und zügigen Entwicklung hilfreich sein und das (Arbeits-) Leben einfacher machen.

Login Box Concept

Login-Box-Concept

Das Login Box Concept ist eine ansprechende Design-Studie, die online auf eigene Bedürfnisse und Farbgebungen angepasst werden kann. In einem Live-Editor kann man direkt den Code bearbeiten und sofort das Ergebnis des neuen Codes sehen. Alle nötigen Dateien stehen zum Download bereit.

Demo und Download

Circular Fly-Out Navigation Menu

Circular-Fly-Out-Navigation-Menu

Eine recht interessante Menügestaltung liefert dieses mit Sass und CSS3 Transitions, Transformations und Animations erstellte Tool. In der einen oder anderen Anwendung dürfte sich das Menü mit Sicherheit wiederfinden. Minimalistische Websites und mobile Anwendungen könnten ein Anwendungsbereich sein.

Demo und Download

3D Folding Panel

3D-Folding-Panel

Das 3D Folding Panel bietet nicht nur einen ansprechenden Effekt, sondern auch ein nützliches Bedienkonzept. Erstellt wurde es mit CSS3 Transformations und jQuery. Quadrate liegen nebeneinander und können beispielsweise als Artikelvorschau dienen. Klickt man auf eines der Quadrate, faltet sich der mittlere Bereich auseinander und zeigt den Content. Das 3D Folding Panel ist voll responsiv und bietet auch auf einem Smartphone seine Vorteile. Websites mit diesem Konzept sind sehr gut vorstellbar.

3D-Folding-Panel-Aktion

Demo und Download

Motion Blur Effect with SVG

Motion-Blur-Effect-with-SVG

Das Tool stellt eine Bewegungsunschärfe mit Wirkung auf HTML-Elemente vor. Die Effekte werden mit JavaScript und einem SVG Blur Filter erreicht. INsgesamt ist das ein sehr schönes Beispiel für Anwendungsbereiche und Umsetzung.

Demo und Download

Fixed Background Effect

Fixed-Background-Effect

Fixed Background Effect ist ein einfaches Beispiel, wie sich die CSS-Eigenschaft „background-attachment“ sinnvoll und ansprechend nutzen lässt, um einen fixen Hintergrund zu realisieren. Eine nützliche Sache, die wir mit Sicherheit auch öfter in der „freien Wildbahn“ sehen werden.

Demo und Download

Pure CSS Questionnaire Concept

Pure-CSS-Questionnaire-Concept

Um die interessanten Effekte zu sehen, muss man mit dem Mauszeiger die einzelnen Elemente berühren. Es zeigt sich eine sehr flüssig laufende Animation des blauen Balkens, gleichzeitig wechselt der Hintergrund des Notebook-Bildschirms. Findige Entwickler werden hierfür sicherlich sinnvolle Anwendungsbereiche finden. Die gezeigten Effekte sind mit reinem CSS3 realisiert worden.

Demo und Download

Elevator.js

Elevator.js

Elevator.js ist witzig und nervig zugleich. Zuerst einmal muss man bei dieser Demo nach ganz unten scrollen und dort dann auf den „nach Oben“-Button klicken. Der relativ langsam animierte Scroll-Effekt wird von Musik begleitet und endet oben mit einem „Schreibmaschinen-Pling“. Ansprechend und einzigartig ist der Effekt schon und mit anderen Scroll-to-Top Scripts auch nicht zu vergleichen.

Demo und Download

Hero Slider via CodyHouse

Hero Slideshow

Die Hero-Slideshow ermöglicht Ihnen relativ einfach, vollflächige Hintergrund-Slideshows zu erstellen. Die Slideshow kann nicht nur vollflächige Hintergrundbilder darstellen, sondern auch Videos und einzelne Elemente ansprechend integrieren.

Hero-Slideshow-tech

Diese Eigenschaften dürften diese Slideshow zu einem Favoriten für die Entwicklung von Websites mit Hero-Bereichen machen.

Demo und Download

Fullscreen Slideshow by Nikolay Talanov

Fullscreen-slideshow

Die Fullscreen-Slideshow kann „nur“ Bilder vollflächig darstellen und diese automatisch mit ansprechenden Effekten wechseln. Wer eine reine Bild-Slideshow mit Animationen und automatischem Start sucht, sollte sich diese Slideshow einmal näher ansehen.

Demo und Download

FSVS – Full Screen Vertical Slider

Full-Screen-Vertical-Scroller

Der Full Screen Vertical Slider ist ein simpler, vollflächiger und vertikal funktionierender Slider, der ausschließlich mit CSS3 Transitions entwickelt wurde. Ein Fallback für Browser, die CSS3 Transitions nicht unterstützen, wurde ebenfalls bedacht und mit etwas jQuery umgesetzt. Bedienen lässt sich der Slider nicht nur über die Punkt-Navigation auf der rechten Seite, sondern auch mit den Pfeiltasten auf der Tastatur, dem Mausrad, normalem Scrollen mittels Trackpad und Touch-Gesten. Das macht den Slider universell einsetzbar, auch im Bezug auf Mobile-First-Anwendungen.

Demo und Download

Simple Responsive Charts – CHARTIST.JS

Chartist

Chartist.js wurde von einer Gemeinschaft entwickelt, die enttäuscht über andere auf dem Markt befindliche Bibliotheken war. Es existieren unzählige weitere Chart-Bibliotheken, doch keine hatte alle Funktionen, die sich die Gemeinschaft wünschte. Also entwickelten sie Chartist.js, um eine Chart-Anwendung zu haben, bei der man nicht mehr nachbessern muss. Die mit Chartist erstellten, ansprechend animierten Visualisierungen sind voll responsiv und daher auch auf mobilen Geräten gut zu verwenden. Die Chart-Bibliothek bietet dem Entwickler sehr viele Möglichkeiten zur Darstellung von Daten. Des Weiteren kann der Entwickler zwischen etlichen Animations-Möglichkeiten wählen.

Chartist-Beispiel

Demo und Download

Interactive Drag and Drop Coloring Concept

Interactive-Coloring-Concept

Unser letzter Kandidat ist kein wirklich nützliches Tool, dafür aber ein sehr gut umgesetztes Experiment. Jeder Bereich der Website kann per Drag und Drop aus der Farbpalette links eigens eingefärbt werden, was auch sehr gut funktioniert. Ein Anwendungsbereich im realen Arbeitsleben könnte zum Beispiel das Testen von verschiedenen Farb-Kombinationen im Zuge der Entwicklung einer Website sein.

Demo und Download

Fazit

Diese Liste zeigt sehr interessante Ansätze und gibt dem Entwickler einige sofort nutzbare Tools an die Hand, mit denen man unmittelbar gute Ergebnisse erzielen kann. Selbst das von uns verlinkte Experiment kann – kreativ eingesetzt – nützliche Dienste im Arbeitsalltag leisten. Kurzum, mit der überwiegenden Anzahl der vorgestellten Tools lassen sich in Null-Komma-Nichts ansprechende Websites erstellen.

Links zum Beitrag

(dpe)

Kategorien
HTML/CSS JavaScript & jQuery Webdesign

Lining.js: Textzeilen verändern per CSS-Selektor

Dank der zahlreich zur Verfügung stehenden CSS-Selektoren kann man per Stylesheets auf fast jedes einzelne HTML-Element innerhalb eines Dokumentes zugreifen. Und dank des Pseudoelementes ::first-line hat man sogar innerhalb eines Textes die Möglichkeit, CSS-Eigenschaften nur auf die erste Zeile anzuwenden – unabhängig davon, ob die Zeile automatisch umgebrochen oder durch manuellen Zeilenumbruch herbeigeführt wird. Da es neben ::first-line aber keine weiteren Selektoren gibt, um auf die zweite, dritte oder letzte Zeile eines Textes zuzugreifen, kann man sich diese noch fehlenden CSS-Selektoren mit der JavaScript-Bibliothek Lining.js nachrüsten.

.line[last] statt ::last-line

Analog zu den Selektoren ::last-child und ::nth-child(), mit denen auf das letzte oder ein anderes beliebige Kindelement zugegriffen werden kann, stellt Lining.js ein ähnliches Verhalten für Textzeilen zur Verfügung. Statt der nicht vorhandenen Selektoren ::last-line und ::nth-line(n) werden die Zeilen über die Klassen .line[last] und .line[index="n"] angesprochen.

liningjs

Ist die JavaScript-Datei im Dokument eingebunden, müssen zunächst die Textelemente, auf die Lining.js angewendet werden soll, mit dem Data-Attribut data-lining ausgezeichnet werden. Einen Wert benötigt das Attribut nicht.

<p data-lining>
  Lorem ipsum …
</p>

Anschließend können über diese Klassen einzelne Zeilen innerhalb eines Textes individuell per CSS ausgezeichnet werden.

p .line[last] {
  color: red;
}

p .line[index="2"] {
 font-weight: bold;
}

liningjs-beispiel1
.line[last] und .line[index="2"] auf einen Text angewendet

Im Beispiel wird die jeweils letzte Zeile eines <p>-Elementes rot gefärbt, während die jeweils zweite Zeile fett dargestellt wird. Obwohl es das Pseudoelement ::first-line gibt, existiert mit .line[first] auch eine Variante für Lining.js. Hier bleibt Ihnen freigestellt, für welche Variante Sie sich entscheiden.

Auch für die Pseudoelemente ::nth-of-type() und ::nth-last-of-type() gibt es mit .line:nth-of-type() und .line:nth-last-of-type() entsprechende Möglichkeiten für Textzeilen.

p .line:nth-of-type(2n) {
  color: green;
}

liningjs-beispiel2
Alternative Zeilen mit .line:nth-of-type(2n)

Im Beispiel wird dank .line:nth-of-type(2n) jede zweite Zeile eines Textes grün angezeigt. Mit dem Selektor .line:nth-last-of-type(2n) erhält man ebenfalls Zugriff auf jede zweite Zeile. Die Zählung beginnt jedoch mit der letzten Zeile statt mit der ersten.

Als letztes gibt es noch den einfachen Selektor .line. Mit diesem kann man CSS-Eigenschaften auf jede Zeile eines Textes anwenden. Dieser Selektor ist dann interessant, wenn man beispielsweise nach jeder Zeile eine Linie zeichnen möchte.

p .line {
  border-bottom: 1px solid blue;
}

liningjs-beispiel3

Linie unterhalb jeder Zeile mit .line

Das Beispiel sorgt dafür, dass nach jeder Zeile eine blaue Linie dargestellt wird. Ohne Lining.js hätte man nur Zugriff auf das <p>-Element als Ganzes und könnte nur den Absatz mit einer Linie versehen.

Standardaussehen definieren

Da nicht jeder Browser Lining.js unterstützt, gibt es zusätzlich die Möglichkeit, das Standardaussehen von Texten unterschiedlich zu definieren. So kann das Aussehen bei Unterstützung von Lining.js anders aussehen als bei Nicht-Unterstützung.

p {
  font-style: italic;
}

.nolining p {
  font-style: normal;
}

Im Beispiel werden zunächst alle <p>-Elemente mit kursiver Schrift ausgezeichnet. Über die Klasse nolining wird dann ein abgewandeltes Aussehen definiert, falls der Browser Lining.js nicht unterstützt.

Lining.js und responsives Layout

Die Zeilen eines Textes werden per Lining.js beim Laden der Seite einmalig festgelegt. Verschieben sich die Zeilen, weil das Browserfenster breiter oder schmaler gemacht wird, bleibt die ursprüngliche Zeileneinteilung und das damit verbundene Aussehen beibehalten. Will man jedoch, dass die Zeilen bei veränderter Größe des Fensters neu eingeteilt werden, muss den jeweiligen Texten das zusätzliche Data-Attribut data-auto-resize zugewiesen werden.

<p data-lining data-autoresize>
  Lorem ipsum …
</p>

Ändert man dann das Browserfenster, sorgt Lining.js dafür, dass die veränderte Zeileneinteilung bei den Pseudoelementen – zum Beispiel .line[index="3"] – berücksichtigt wird.

Lining.js nur auf bestimmte Zeilen anwenden

Technisch funktioniert Lining.js so, dass jede Zeile eines Textes mit dem Element <text-line> umschlossen wird. Diese Umwandlung kann gerade bei langen Texten durchaus ein Weilchen dauern. Will man Lining.js gar nicht auf den gesamten Text anwenden, kann man die Umwandlung in einzelne Zeilen auf einen bestimmten Textbereich begrenzen. Mit den Data-Attributen data-from und data-to geben wir einen Bereich an, der in einzelne Zeilen umgewandelt werden soll.

<p data-lining data-from="5">
  Lorem ipsum …
</p>

Im Beispiel werden nur die fünfte und alle folgenden Zeilen des Absatzes berücksichtigt. Entsprechend lassen sich die Selektoren auch nur auf diesen Bereich anwenden.

Animierte Effekte zum Ein- und Ausblenden

Neben der eigentlichen Möglichkeit, auf einzelne Textzeilen zuzugreifen, gibt es eine ergänzende JavaScript-Bibliothek, mit der wir animierte Effekte auf die Zeilen anwenden. So lassen sich Texte Zeile für Zeile auf unterschiedliche Weise ein- und ausblenden. Die Datei lining.effects.js muss dafür mit eingebunden werden. Anschließend stehen einem die Ein- und Ausblendeffekte zur Verfügung. Sie werden über das Data-Attribut data-effect angesprochen.

<p data-lining data-effect="rolling">
  Lorem ipsum …
</p>

liningjs-beispiel4

Einblendeffekt rolling

Im Beispiel wenden wir den Effekt rolling auf einen Text an. Dabei werden die einzelnen Zeilen von der ersten Zeile beginnend nach unten geklappt. Insgesamt stehen sieben verschiedene Einblendeffekte zur Verfügung – vom einfachen Fade-in und Slide-in bis hin zum komplexen metroRotateIn, bei dem die Zeilen per 3D-Drehung und Fade-in eingeblendet werden.

Fazit

Lining.js ist ein sehr gut durchdachtes und umfangreiches Werkzeug, das eine individuelle Gestaltung von Texten beziehungsweisen dessen Zeilen ermöglicht. Die schicken Animationseffekte runden den Funktionsumfang der Bibliothek gut ab. Zusätzlich zur Auszeichnung per Data-Attribute ist auch eine ausschließliche Konfiguration per JavaScript möglich.

Lining.js läuft in allen gängigen Versionen von Chrome, Safari und Opera. Kleiner Wermutstropfen: Der Internet Explorer wird derzeit gar nicht unterstützt. Die Bibliothek steht wie viele dieser Art unter der MIT-Lizenz kostenlos zur Verfügung.

Dank einer guten Dokumentation und einigen Beispielen ist der Einstieg in Lining.js einfach.

(dpe)

Kategorien
Design Editoren HTML/CSS JavaScript & jQuery Programmierung Responsive Design UI/UX Webdesign

Zehn frische Tools für Webdesigner und Entwickler (Ausgabe Mai 2015)

Webdesigner sind immer auf der Suche nach neuen Helferlein, die ihnen das Leben erleichtern. Dabei ist es zunächst einmal egal, um was es sich handelt. Ob es ein Online-Tool ist oder ob es sich um neue Ressourcen handelt, gebrauchen kann man fast alles irgendwann. Wir haben uns daher einmal im Netz umgesehen und neue, wirklich frische Tools aus diesem Monat für Sie ausgesucht. Dabei herausgekommen ist eine gute Mischung von Tools zum Testen von Code, ein neuer HTML-Editor und vieles mehr, von dem wir annehmen, dass es Ihnen gefallen wird.

tools-webdesigner-teaser_DE

1. Visual Studio Code

MS-Visual-Studio-Code

Microsoft öffnet sich immer weiter und produziert einen neuen und plattformübergreifenden Code-Editor. Der Editor versteht sich nicht als umfassende Entwicklungsumgebung, sondern als kleiner, aber feiner Code-Editor für alle modernen Web- und Cloud-Anwendungen. Der Editor wird für Windows, Linux und Mac OS X angeboten und soll mit Apps wie SublimeText 2 konkurrieren können, sobald die fertige Version angeboten wird. Der Editor befindet sich noch in einer „Preview“-Phase.

2. Colour Shades Generator

Colour-Shades-Generator

Der Colour Shades Generator zeigt Ihnen die optimalen Schatten-Farben für die Arbeit mit CSS-Shadows an, nachdem Sie einen Farbcode eingegeben haben. Um eine der dargestellten Farben zu kopieren, müssen Sie nur darauf klicken.

3. CSS Dig

CSS-Dig

Diese praktische Chrome Extension bietet eine alternative Möglichkeit, Ihr CSS zu analysieren und Korrekturen und Verbesserungen vorzunehmen. Alle Eigenschaften werden mit ihren Selektoren angezeigt. So findet man unter Umständen doch noch Verbesserungspotential in einer CSS-Datei.

4. Think with Paper

Think-with-Paper

Paper ist eine Zeichen-App für das iPad, mit dem Sie Diagramme mit geraden Linien, Formen und Objekte aller Art erstellen können. Freihändig sind Kreise und Dreiecke möglich, die sich jederzeit ändern lassen. Das Tool ist sehr gut dafür geeignet, um Ideen zu erfassen oder Mockups zu erstellen. Die App ist kostenlos erhältlich. Wir haben das Tool bereits in einer frühen Version ausführlicher vorgestellt.

5. HTML Arrows

HTML-Symbols-Entities-and-Codes

HTML Arrows bietet entgegen dem Namen nicht nur die Pfeilsymbole für die Nutzung im HTML-Quellcode an, sondern eine ganze Menge anderer, nützlicher Symbole ebenfalls. Diese Website sollte jeder Webdesigner und Webentwickler in seine Lesezeichen aufnehmen. Alle gebräuchlichen HTML-Zeichen sind komplett mit Code enthalten.

6. TouchDevelop

TouchDevelop

TouchDevelop ist ein weiteres Tool aus Microsofts sich öffnendem Portfolio. TouchDevelop ermöglicht sowohl Anfängern als auch erfahrenen Programmierern, Apps mit ihrem Handy, Tablet oder einer Desktop-Umgebung zu schaffen. Man kann aus drei Schwierigkeitsstufen vom Anfänger bis hin zum Profi auswählen. Die Drag-and-Drop-Oberfläche des Tools ermöglicht eine einfache Gestaltung einer App. Entwickelt wurde das Tool, um Menschen das Programmieren näher zu bringen und Ihnen einen leichten Einstieg in die App-Programmierung zu bieten. Je nach Wissensstand ersetzen Sie nach und nach die Nutzung des Drag-and-Drop-Editors durch das Einbringen eigenen Codes. Wie Visual Studio-Code ist TochDevelop ein plattformübergreifendes Angebot, das auf Android, iOS, Windows Phone, Windows, Linux und Mac verfügbar ist.

7. ES Feature Tests

ES-Feature-Tests

ES Feature Tests ermöglicht Ihnen, faktengestützt den besten Code an jeden Browser auszuliefern. Natives ECMAScript 6 geht an kompatible Browser, ein Fallback existiert. Hier finden Sie eine Kompatibilitätsübersicht. Das Tool bietet Funktionstests für jeden Browser.

8. Vorlon.js

Vorlon.JS

Debuggen und testen Sie Ihr JavaScript mit diesem Tool auf Basis von node.js und socket.io. Sie können sich remote auf bis zu 50 Geräte simultan schalten und Ihren Code ausführen, um Performance zu testen und Fehler zu beheben. Vorlon.js ist ein Weg zum Debuggen Ihres Codes auf annähernd jeder Plattform. Vorlon.js ist Open-Source und kostenlos. Plugins zur Erweiterung der Funktionalität sind ebenfalls erhältlich. Auch dieses Tool entstammt dem Microsoft-Kosmos.

9. Ionic

Ionic Framework

Ionic befand sich bereits einige Zeit im Beta-Stadium, ging jedoch in diesem Monat offiziell mit der endgültigen Version 1.0.0 ‚uranium-unicorn‘ online. Ionic ist eine Open-Source-Bibliothek mit mobil-optimierten HTML, CSS und JS Komponenten, Gesten und Tools für die Erstellung von interaktiven Apps. Entwickelt wurde Ionic mit Sass. Es ist optimiert für Angular.js.

10. RightFont

RightFont-for-Mac App

Sollten Sie extrem viele Fonts auf Ihrem Mac haben, könnte diese App für Mac OS X für Sie sinnvoll sein. RightFont ermöglicht Ihnen die Kontrolle über alle Schriftarten auf Ihrem Mac. Die App gibt Ihnen den Zugriff direkt von der Menü-Bar aus und integriert die Schriftarten in Photoshop und Sketch 3. Die Fonts können nach unterschiedlichen Kriterien organisiert werden, etwa nach Serif oder Sans-Serif, Google oder Typekit, Breite, Font-Gewicht und vielem mehr.

Links zum Beitrag

(dpe)

Kategorien
JavaScript & jQuery Webdesign

Fetch-API: Einfaches Laden von Inhalten ohne XMLHttpRequest

Komplexe Web-Applikationen setzen zunehmend auf JavaScript. Dabei werden auch Inhalte immer häufiger per JavaScript geladen. Bislang erfolgte dies über ein XMLHttpRequest-Objekt, was aber immer vergleichsweise umständlich war. So sind hierzu die Methoden open() und send() notwendig, um Inhalte zu laden. Per Callback-Funktion, die über einen Event-Listener aufgerufen wird, können die Inhalte dann abgerufen werden. Die neue Fetch-API vereinfacht das Laden von Inhalten deutlich.

fetchapi-teaser_DE

Laden mit fetch() und then()

Nicht immer sind die umfangreichen Möglichkeiten von XMLHttpRequest notwendig. Gerade, wenn es darum geht, ein JSON-Objekt oder einen einfachen Text aus einer Datei zu laden, war das XMLHttpRequest-Objekt immer schon überdimensioniert. Dennoch gab es keine Alternative dazu.

var beispiel = new XMLHttpRequest();

beispiel.open("GET", "beispiel.txt", true);
beispiel.send();

beispiel.addEventListener("readystatechange", function () {
  if (this.readyState == 4) {
    console.log(this.responseText);
  }
}, false);

Das Beispiel zeigt das recht umständliche Verfahren, um eine einfache Textdatei zu laden und deren Inhalt in der Konsole auszugeben. Während per open() die Art und URL des Requests definiert wird, wird er über send() ausgeführt. Per addEventListener() wird auf die Antwort des Servers gewartet und per readyState wird der Status des Request abgefragt. Wird der Statuscode 4 ausgegeben, war der Request erfolgreich und der Inhalt wird per responseText ausgegeben.

Die neue Fetch-API hat einen anderen Ansatz. Anders als XMLHttpRequest ist die Fetch-API in erster Linie für das Empfangen von Inhalten gedacht. Darüber hinaus kommt die Fetch-API ohne Event-Listener aus. Stattdessen werden sogenannte Promises verwendet, um die Inhalte nach erfolgreichem Request auszulesen.

Während man also per fetch()-Methode beispielsweise eine einfache Textdatei oder ein JSON-Objekt lädt, wird mit der Promise-Methode then() die Antwort des Requests verarbeitet.

fetch("beispiel.txt").then(
  function (antwort) {
    return antwort.text(); 
  }
).then(
  function (text) {
    console.log(text);
  }
);

Das Beispiel zeigt, wie die fetch()-Methode zusammen mit Promises – also der then()-Methode – funktioniert. Per fetch() wird zunächst der Request abgesetzt. Im Beispiel wird eine einfache Textdatei aufgerufen. War die Methode erfolgreich, wird per then() eine Funktion ausgeführt. Dieser wird die Antwort des Requests übergeben. Die Antwort ist in diesem Fall der Inhalt der Textdatei beispiel.txt. Per text() wird die Antwort als reiner Text bereitgestellt und ausgegeben.

Es folgt eine zweite then()-Methode, die dann ausgeführt wird, wenn die Bereitstellung der Antwort als Text erfolgreich war. Diese zweite then()-Methode gibt letztendlich den Text in die Konsole aus.

Alternativ ist es auch möglich, ein JSON-Objekt per Fetch-API auszulesen. Hierbei wird der Funktion der ersten then()-Methode die Antwort des Requests als JSON bereitgestellt.

fetch("beispiel.json").then(
  function (antwort) {
    return antwort.json(); 
  }
).then(
  function (json) {
    console.log(json["beispiel"]);
  }
);

Über die zweite then()-Methode erhält man im Beispiel den Zugriff auf das JSON-Objekt. Hier wird der Wert der JSON-Eigenschaft beispiel in die Konsole geschrieben.

Metadaten des Fetch-Requests auslesen

Jeder Fetch-Request besitzt eine Reihe von Metadaten, die ausgelesen werden können. Dazu gehören die Eigenschaften status, statusText, url und type.

fetch("beispiel.json").then(
  function (antwort) {
    console.log(antwort.status);
    console.log(antwort.statusText);
    console.log(antwort.url);
    console.log(antwort.type);
  }
)

Die Eigenschaft status gibt den HTTP-Statuscode wieder. Wird die per fetch()-Methode aufgerufene Datei erfolgreich geladen, wird 200 zurückgegeben. Nur in diesem Fall würde auch ein etwaiger zweiter Promise – also eine zweite then()-Methode – ausgeführt. Die Eigenschaft statusText gibt den HTTP-Status als Text zurück, im Erfolgsfall also OK.

Die Eigenschaft url hingegen gibt die in der fetch()-Methode angegebene URL aus. Als Letztes exisitiert noch die Eigenschaft type, welche darüber informiert, woher der Request stammt. Wird der Wert basic ermittelt, stammt der Request von derselben Domain. Der Wert cors siganlisiert, dass die Antwort von einer fremden Domain stammt, welche im Rahmen des Cross-Origin-Resource-Sharings (CORS) jedoch den Zugriff durch den Server, der den Request abgesetzt hat, erlaubt.

Als letzter möglicher Wert für status kann opaque existieren. Dies bedeutet, dass die Antwort von einer fremden Domain kommt, die keine Berechtigung für das Cross-Origin-Resource-Sharing erteilt hat. Der Inhalt kann dementsprechend nicht gezeigt werden.

Außerdem hat man per headers.get() die Möglichkeit, jeden einzelnen HTTP-Header der Antwort auszulesen.

console.log(antwort.headers.get("Content-Type"));

Im Beispiel wird der Header Content-Type ausgelesen und in die Konsole geschrieben.

Eigenschaften für fetch()-Aufruf definieren

Über einen Aufruf der Fetch-API lassen sich auch diverse Eigenschaften festlegen. Diese werden in Form eines Literalobjekts als zweiter Parameter der fetch()-Methode hinzugefügt. So kann man beispielsweise den Modus des Requests festlegen. Über mode bestimmt man, ob der Request ausschließlich im Rahmen der Same-Origin-Policy von derselben Domain zugelassen werden (same-origin) oder ob auch Fremddomains erlaubt sein sollen, sofern sie im Rahmen des Cross-Origin-Resource-Sharings den Zugriff zulassen.

fetch("http://example.com/beispiel.json", {
  mode: "cors"
}).then(
  …
)

Im Beispiel wird der Modus auf cors gesetzt. Es werden also fremde Domains zugelassen.

POST-Request absetzen

Neben dem einfachen Laden von Inhalten erlaubt die Fetch-API auch das Absetzen von POST-Requests. Über die Eigenschaft method kann die fetch()-Methode einen POST-Request initiieren. Über die Eigenschaft body überträgt man Inhalte. So hat man die Möglichkeit, dem Request Parameter mitzugeben und kann die Antwort des Requests je nach übergebenem Parameter beeinflussen.

fetch("beispiel.json", {
  mode: "cors",
  method: "post",
  body: "seite=kontakt&benutzer=hans",
  headers: { 
    "Content-Type": "text/plain" 
  }
}).then(
  …
)

Im Beispiel werden per body Parameter mit dem Request übergeben. Zusätzlich ist es möglich, HTTP-Header anzugeben. Im Beispiel wird der Content-Type definiert.

Browser-Support

Da die Fetch-API noch recht neu ist, können noch nicht alle Browser etwas mit ihr anfangen. Derzeit wird sie nur von Chrome ab Version 42 unterstützt. Firefox wird sie ab Version 39 unterstützen. Für den Internet Explorer und Safari ist derzeit keine geplante Unterstützung bekannt. Daher ist die Fetch-API zum jetzigen Zeitpunkt für den produktiven Einsatz noch nicht geeignet.

(dpe)

Kategorien
Bilder & Vektorgrafiken bearbeiten Design HTML/CSS JavaScript & jQuery Webdesign

Flexibel: Vivus-Framework animiert SVG mit JavaScript

Dass mit dem SVG-Format in Kombination mit JavaScript anspruchsvolle und schicke Animationen möglich sind, beweisen die vielen Frameworks, die solche Animationen realisieren. Vivus reiht sich ein in diese Liste. Statt mit umwerfenden 3D-Effekten zu punkten, geht Vivus einen anderen Weg: Das Framework sorgt dafür, dass mehr oder weniger einfache Strichgrafiken per Animation gezeichnet werden. Dank einiger Einstellungsmöglichkeiten wird so aus einer ziemlich simplen Grafik ein sehr ansehnlicher Effekt.

vivus1

Voraussetzung für eine animierte Strichgrafik

Damit aus einer statischen SVG-Grafik mit Vivus eine Animation wird, müssen die zu animierenden Formen eine sichtbare Kontur besitzen. Denn Vivus animiert nur die Kontur eines SVG-Elementes. Daher sollte eine Form immer ohne Füllung vorliegen. Dazu genügt es, den Formen die Eigenschaft „fill: none“ hinzuzufügen.

Technisch erfolgt die Animation per Stylesheet. Dazu werden die CSS-Eigenschaften „stroke-dasharray“ und „stroke-dashoffset“ verwendet. Die beiden Eigenschaften dienen eigentlich dazu, gestrichelte Linien darzustellen. Die Werte für die beiden Eigenschaften beschreiben die Länge eines Strichs sowie den Abstand zwischen den Strichen. Vivus nutzt diese Eigenschaften, um einer Form eine gestrichelte Linie zuzuweisen, bei der der Abstand („stroke-dashoffset“) per „animation“-Eigenschaft von 1000 auf 0 reduziert wird. Der Wert für „stroke-dasharray“ wird dabei so gewählt, dass die gestrichelte Linie der Form nur einen Strich aufweist.

Da sich die beiden genannten CSS-Eigenschaften nur auf „<path>“-Elemente anwenden lassen, muss neben der Datei „vivus.js“, welche für die eigentliche Animation zuständig ist, auch die Datei „pathformer.js“ im HTML-Dokument eingebunden werden. Pathfinder sorgt dafür, dass alle SVG-Formen von Vivus automatisch in ein „<path>“-Element umgewandelt werden.

SVG-Grafik per Vivus animieren

Für eine Animation muss zunächst eine SVG-Grafik in einem HTML-Dokument verfügbar gemacht werden. Damit es später per Vivus animiert werden kann, defineiren wir auch eine ID, über die die Grafik später ansprechbar ist.

<svg id="strichgrafik">
  <path stroke="blue" stroke-width="2" fill="none" d="…" />
  <rect stroke="blue" stroke-width="2" fill="none" x="0" y="0" width="100" height="200" />
</svg>

Im Beispiel werden ein „<path>“-Element sowie ein Rechteck per SVG definiert. Anschließend wird per JavaScript der Grafik die Vivus-Animation hinzugefügt.

new Vivus("strichgrafik", {type: "delayed", duration: 500}, callback);

Dies geschieht, indem wir ein neues „Vivus()“-Objekt erstellen. Erwartet werden mindestens zwei Parameter. Der erste ist die ID der SVG-Grafik. Es folgt ein Literalobjekt mit verschiedenen Einstellungen für die Animation. Optional kann noch eine Callback-Funktion angegeben werden, die nach Beendigung der Animation ausgeführt wird.

Per „type“ geben wir die Art der Animation an. Der Wert „delayed“ sorgt dafür, dass die Animation die in „duration“ angegebene Dauer lang ist. Dabei werden alle Formen mit einem kleinen zeitlichen Versatz gleichzeitig gezeichnet. Der Wert für „duration“ ist dabei nicht in Sekunden oder Millisekunden angegeben, sondern in Frames. Mit dem Typ „async“ startet die Animation alle Formen ohne zeitlichen Versatz.

Neben „delayed“ und „async“ gibt es noch den Wert „oneByOne“. Dieser sorgt dafür, dass alle Formen nacheinander gezeichnet werden – im Beispiel also erst der Pfad und anschließend das Rechteck. Der Wert für „duration“ gilt hier für jede zu zeichnende Form.

vivus2
Eine SVG-Grafik unterschiedlich animiert

Die Formen werden in der Reihenfolge animiert, wie sie in der SVG-Grafik angelegt sind.

Individuelle Animation mit einem „Szenario“

Als letztes gibt es noch den Typ „scenario“. Hierbei hat man die Möglichkeit, die Animation für jede einzelne Form einer SVG-Grafik individuell anzugeben.

new Vivus("strichgrafik", {type: "scenario", duration: 500}, callback);

Für die einzelnen Formen der SVG-Grafik lassen sich nun per Data-Attribut ein Startpunkt („data-start“) sowie eine Dauer („data-duration“) für die Animation definieren.

<svg id="strichgrafik">
  <path data-start="500" data-duration="750" stroke="blue" stroke-width="2" fill="none" d="…" />
  <rect data-start="0" data-duration="1500" stroke="blue" stroke-width="2" fill="none" x="0" y="0" width="100" height="200" />
</svg>

Im Beispiel startet die Animation für den Pfad bei 500 Frames und dauert 750 Frames. Das Data-Attribut „data-duration“ überschreibt hierbei die im JavaScript angegebene Dauer.

Eine Alternative für „scenario“ ist „scenario-sync“.

new Vivus("strichgrafik", {type: "scenario-sync", duration: 500}, callback);

Bei dieser Form wird kein absoluter Startwert angegeben, sondern ein Delay. Dieser Delay beschreibt die Zeit, die zwischen dem Ende der vorherigen Animation und dem Start einer neuen Animation vergehen soll.

<svg id="strichgrafik">
  <path data-delay="0" data-duration="750" stroke="blue" stroke-width="2" fill="none" d="…" />
  <rect data-delay="250" data-duration="1500" stroke="blue" stroke-width="2" fill="none" x="0" y="0" width="100" height="200" />
</svg>

Im Beispiel beginnt die Animation des Pfades sofort. Das Rechteck wird 250 Frames nach Ende der Pfadanimation animiert. Gerade bei vielen zu animierenden Formen kann es einfacher sein, mit diesem Typ zu arbeiten.

Animationsstart definieren

Normalerweise startet die Animation der SVG-Grafik automatisch. Da eine Grafik mitunter erst durch Scrollen sichtbar wird, gibt es die Möglichkeit, die Animation erst dann zu starten, wenn sich die Grafik im Viewport des Browsers befindet. Dazu wird der Eigenschaft „start“ der Wert „inViewport“ hinzugefügt.

new Vivus("strichgrafik", {type: "scenario", duration: 500, start: "inViewport"}, callback);

Mit dem Wert „manual“ ist es zudem möglich, ein automatisches Starten der Animation ganz zu unterbinden. Das ist nützlich, wenn die Animation per Buttonklick gestartet werden soll. Um die Animation manuell steuern zu können, ist es wichtig, dass der „Vivus()“-Aufruf einer Variablen zugeordnet wird.

var grafik = new Vivus("strichgrafik", {type: "delayed", duration: 100, start: "manual"});

Anschließend kann man die Steuerfunktion für die Animation einem Button zuordnen.

document.getElementById("button").addEventListener("click", function() {
  grafik.play();
}, false);

Im Beispiel wird per „play()“ die Animation per Klick auf einen Button gestartet. Die Animationsgeschwindigkeit kann der Methode „play()“ optional hinzugefügt werden. Werte zwischen 0 und 1 spielen die Animation langsam ab, Werte darüber schnell. Ein negativer Wert sorgt dafür, dass die Animation rückwärts läuft.

Neben der „play()“-Methode gibt es „stop()“ zum Anhalten der Animation und „reset()“, um zum Startpunkt der Animation zurückzukehren.

Browsersupport

Vivus läuft auf allen gängigen Browsern. Wie so oft macht der Internet Explorer einige Probleme. So ist es notwendig, beim Internet Explorer die Pfade bei jedem Animationsframe neu zu zeichnen. Das sorgt natürlich für einen höheren Ressourcenverbrauch, wird aber auch nur beim Internet Explorer so gemacht. Außerdem lässt sich dieses ständige Rendern per „forceRender“ ausschalten – mit dem Risiko, dass es in Microsofts Browser nicht mehr richtig läuft.

Vivus kommt ohne weitere Bibliotheken wie beispielsweise jQuery aus und wird unter der MIT-Lizenz abgegeben. Das Framework kann also kostenlos für eigene Projekte eingesetzt werden.

Link zum Beitrag

(dpe)

Kategorien
JavaScript & jQuery Webdesign

JavaScript: echte Typografie im Web mit Type.js

Schöne und korrekte Typografie ist zuweilen ein schwieriges und aufwändiges Unterfangen. Alle typografischen Regeln und Gepflogenheiten zu berücksichtigen, ist nicht immer einfach und im Webdesign nicht immer machbar. Zwar gibt es dank CSS viele Möglichkeiten, Texte typografisch eindrucksvoll zu gestalten. Allerdings ist man trotz der stets wachsenden Möglichkeiten immer noch weit von den Typografiewerkzeugen entfernt, die zum Beispiel Layoutprogamme wie InDesign bereitstellen. Mit der JavaScript-Bibliothek „type.js“ kann man immerhin eine Vielzahl typografischer Funktionen hinzufügen – für eine bessere Webtypografie.

Type.js

„type.js“ per CSS nutzen

Der Einsatz von „type.js“ ist relativ simpel. Ist die JavaScript-Datei im HTML-Dokument eingebunden, nutzt man die typografischen Funktionen der Bibliothek per CSS. „type.js“ stellt nämlich eigene CSS-Eigenschaften zur Verfügung, die wie native Eigenschaften verwendet werden können.

Mit „type.js“ lassen sich unter anderem Regeln für Zeilenumbrüche festlegen und individuelles Kerning für Buchstabenpaare angeben.

typejs

Derzeit gibt es zwei Einschränkungen bei der Verwendung von „type.js“. Zum einen funktioniert es nicht mit externen Stylesheet-Dateien; zum anderen werden auch Inline-Stylesheets nicht unterstützt. Der Abschnitt mit den Style-Angaben muss am Ende des HTML-Dokumentes vor Einbindung der JavaScript-Datei erfolgen.

<style>
  p {
    …
  }
</style>

<script src="type.js"></script>

Zwar gibt es die Möglichkeit, innerhalb der JavaScript-Datei den Parameter „externalCSS“ auf „true“ zu setzen, um auch mit externen Stylesheet-Dateien zu arbeiten. Hierbei werden jedoch alle externen Stylesheets zweimal heruntergeladen – einmal vom Browser, wie es üblich ist, und ein weiteres Mal von „type.js“, um diese auslesen und interpretieren zu können.

Zeilenumbrüche vermeiden

Nicht jeder Zeilenumbruch am Ende einer Spalte ist typografisch sinnvoll. So sollte man zusammenhängende Wörter, die beispielsweise fett oder kursiv ausgezeichnet sind, nach Möglichkeit nicht trennen. Daher gibt es mit „rag-adjust“ eine Eigenschaft, mit der das Verhalten von Zeilenumbrüchen festgelegt werden kann.

p {
  rag-adjust: emphasis;
}

Weist man „rag-adjust“ den Wert „emphasis“ zu, sorgt „type.js“ dafür, dass die letzten drei Wörter eines Wortblockes, der fett oder kursiv ausgezeichnet ist, nie durch einen Zeilenumbruch voneinander getrennt werden. Dieser Wortblock muss per „<strong>“, „<em>“, „<b>“ oder „<i>“ ausgezeichnet sein. Ein „<span>“-Element, welches per CSS fett oder kursiv dargestellt wird, wird von „type.js“ nicht berücksichtigt.

typejs_rag-adjust

Von „type.js“ gesetzt geschützte Leerzeichen verhindern ungewollte Zeilenumbrüche

Um den Zeilenumbruch zu verhindern, ersetzt „type.js“ das Standard-Leerzeichen durch ein geschütztes Leerzeichen („&nbsp;“).

Alternativ besteht die Möglichkeit, einen Zeilenbruch grundsätzlich vor allem Wörtern, die weniger als vier Zeichen lang sind, zu verhindern. Hierzu wird der Eigenschaft der Wert „small-words“ zugewiesen. Der Wert „dashes“ sorgt dafür, dass nach Gedanken- und Bindestrichen ein Zeilenumbruch verhindert wird.

Darüber hinaus gibt es die Möglichkeit, Zeilenumbrüche vor Präpositionen zu verhindern. Dazu wird der Eigenschaft der Wert „prepositions“ zugewiesen. Hierbei werden jedoch nur englischsprachige Präpositionen berücksichtigt. Will man alle vier Regeln zur Vermeidung von Zeilenumbrüchen anwenden, genügt es, der Eigenschaft „rag-adjust“ den Wert „all“ zuzuweisen.

Kurze letzte Zeilen vermeiden

Neben den genannten unschönen Zeilenumbrüchen sollte immer auch verhindert werden, dass die letzte Zeile eines Absatzes zu kurz ausfällt. Auch hierfür stellt „type.js“ mit der Eigenschaft „widow-adjust“ eine Möglichkeit zur Verfügung. Dank „widow-adjust“ wird verhindert, dass die letzte Zeile eines Absatzes weniger als 14 Zeichen lang ist. Auch hierbei gibt es mehrere Werte für die Eigenschaft.

Die Werte „padding-left“ und „padding-right“ ergänzen entweder links oder rechts einen Innenabstand, der so groß ist, dass immer genügend Zeichen in der letzten Zeile eines Absatzes stehen.

p {
  widow-adjust: padding-right;
}

Alternativ kann man mit dem Wert „word-spacing“ den Wortabstand innerhalb eines Absatzes so weit verringern, dass die letzte Zeile eine ausreichende Zeichenlänge hat. Als letzte Möflichkeit bietet sich noch „non-breaking-space“ an. Dieser Wert sorgt dafür, dass zwischen die letzten drei Wörter eines Absatzes geschützte Leerzeichen gesetzt werden.

typejs_widow-adjust

Ein von „type.js“ erreichneter Wert für „padding-right“ (grün dargestellt) verhindert zu kurze letzte Zeilen

Eigenes Kerning für Zeichenpaare festlegen

Als Kerning bezeichnet man die individuellen Zeichenabstände zwischen Buchstabenpaaren. Für jede Buchstabenkombination sind dabei in einer Schrift Zeichenabstände definiert. Diese sorgen dafür, dass zwischen den Buchstaben ausgewogene Abstände für ein stimmiges Schriftbild stehen. Gerade bei großen Schriftgrößen können die in der Schrift festgelegten Abstände aber schon mal zu groß ausfallen, so dass nachjustiert werden muss.

„type.js“ ermöglicht es, für bestimmte Buchstabenkombinationen eigene Abstände festzulegen. Diese werden per „letter-spacing“-Eigenschaft bei jedem Vorkommen des Paares ausgezeichnet.

p {
  kerning-pairs: or 0.5em;
}

Die Eigenschaft „kerning-pairs“ erwartet immer zwei Werte. Als erstes wird das Buchstabenpaar festgelegt, dann folgt der Abstand.

typejs_kerning-pairs

Individuelle Zeichenabstände werden per „letter-spacing“-Eigenschaft ausgezeichnet

Mindest- und Höchstwerte für Schriftgrößen

Die relativ neue CSS3-Einheit „vw“ ermöglicht es, eine Schriftgröße in Relation zur Breite des Viewports festzulegen. Dies kann bei sehr schmalen Viewports zu sehr kleinen Schriftgrößen führen und bei sehr breiten Viewports zu entsprechend großen Schriftgrößen. Mit den „type.js“-Eigenschaften „min-font-size“ und „max-font-size“ lassen sich Mindest- und Höchstwerte für eine Schriftgröße definieren.

p {
  font-size: 4vw;
  min-font-size: 15px;
  max-font-size: 45px;
}

Das Beispiel sorgt dafür, dass die Schrift immer eine Größe zwischen 15 und 45 Pixel hat.

Fazit und Link zum Beitrag

„type.js“ ist durchaus eine Bereicherung für alle, die viel Wert auf eine anspruchsvolle Typografie im Webdesign legen. Die Bibliothek aus der Feder von Nathan Ford steht zum kostenlosen Download via Github zur Verfügung.

Leider hat er bislang keine Angaben zur Lizenz gemacht. Wahrscheinlich ist, dass er lediglich vergessen hat, die Info hinzuzufügen. Dennoch sollten Sie vor einem kommerziellen Einsatz um die Erlaubnis bitten.

(dpe)

Kategorien
Boilerplates & andere Tools JavaScript & jQuery Programmierung Sonstige Programmiersprachen

Neu und kostenlos: Microsofts Editor Visual Studio Code für Windows, Mac und Linux

Mehr denn je öffnet sich Microsoft der Außenwelt. Auf der hauseigenen Build-Konferenz präsentierte Microsoft den neuen Code-Editor „Visual Studio Code“, der kostenlos verteilt wird. Als kleine Sensation darf gewertet werden, dass der Editor nicht nur für Windows, sondern auch für Mac OS X und Linux erhältlich ist. Visual Studio Code versteht sich hierbei nicht als komplette Entwicklungsumgebung wie sein großer Bruder Visual Studio, sondern als „leichte“ Variante im Stil von Sublime Text oder Atom. Schon in der Vergangenheit hatte Microsoft solche kleinen Lösungen im Angebot, aber stets limitiert auf Windows-User und Microsoft-Sprachen. Damit ist nun offenbar Schluss…

Microsofts Code-Editor Visual Studio Code für alle Betriebssysteme

Microsoft Visual Studio Code

Microsoft öffnet sich immer weiter und entwickelt nun auch im Developerbereich Applikationen für andere Betriebssysteme. Auf der offiziellen Haus-Entwicklerkonferenz Build stellte Microsoft völlig überraschend den neuen Code-Editor „Visual Studio Code“ vor. Der Editor befindet sich noch im „Preview“-Status. Es sind also noch nicht alle Funktionen integriert und es funktioniert noch nicht alles 100%ig reibungslos. Doch der erste Eindruck ist schon mal recht positiv und der Funktionsumfang brauchbar. Auch wenn der Editor für die Bearbeitung von ASP.NET und Node.js angepriesen wird, so kann er doch bedeutend mehr.

Die HTML- und JavaScript-Dateien des Editors werden mittels Chromium gehostet, der Open-Source-Variante von Googles Webbrowser Chrome. Allerdings wird der Umweg über das quelloffene Electron-Framework gegangen, aus dem der Atom-Editor entstanden ist. Der Vorteil dieses Weges ist, dass man die App direkt starten kann und nicht installieren muss. Das funktioniert unter allen Betriebssystemen.

MacWinLinux2

An den Funktionsumfang von Visual Studio kommt Visual Studio Code natürlich nicht heran. Das ist naheliegenderweise auch nicht beabsichtigt. Entwickelt wurde der Code-Editor für das Entwickeln und Debuggen von Cloud- und Webanwendungen. Der zurzeit noch rudimentäre Debugger ist aktuell nur für Node.js-Projekte nutzbar.

Microsoft Visual Studio Code
Debugging mit Visual Studio Code

Visual Studio Code bietet bereits in der Preview-Version Syntax-Highlighting für mehr als 20 Sprachen, IntelliSense Auto-Vervollständigung, Bracket Matching, anpassbare Keyboard-Shortcuts, Steuerung per Kommandozeile, automatische Einrückung und Snippet-Support. Unter anderem werden HTML5, CSS 3 und PHP unterstützt.

Visual Studio Code – Look and Feel

Der Editor erinnert stark an den Sublime Text 2 Editor und kann ebenfalls auf persönliche Bedürfnisse angepasst werden. Sehr praktisch ist die Möglichkeit, das Editor-Fenster zu teilen, um mehr als eine Datei gleichzeitig bearbeiten zu können.

visual-studio-code-unterteilt

Visual Studio Code kommt zurzeit mit 2 Themes daher, einem dunklen und einem hellen. Diese lassen sich entweder über das Menü oder über die Kommando-Zeile abrufen und einstellen.

theme-wechsel

Die Code-Vervollständigung funktioniert reibungslos und schnell. Hier geht Microsoft den richtigen Weg. Allerdings ist anzumerken, dass die Vervollständigung nur mit der Sprache funktioniert, die das Dateiformat vorgibt. Bei PHP existieren noch grundsätzliche Schwächen, bei gemischten Dateien wie WordPress-Theme-Templates ist man leider noch auf überwiegende Handarbeit angewiesen. Vielleicht bietet die Zukunft eine Erweiterung für die WordPress-Theme-Entwicklung.

Sehr gut funktioniert die Code-Vervollständigung mit reinen CSS- oder HTML-Dateien.

css-vervollstaendigung

html-vervollstaendigung

Integrierte Git Versions-Kontrolle

Sehr hilfreich kann die integrierte Git-Versionskontrolle sein. Ein einfaches Erstellen von Branches, Push, Pull und Synchronisation ist kein Problem.

GitVersionControl

Visual Studio Code und der Datenschutz

Visual Studio Code befindet sich noch im offiziellen Vorschau-Status. Programmabstürze und Freezes  können daher noch vorkommen. Wer sich zu diesem Zeitpunkt den Editor herunterlädt, erklärt sich damit einverstanden, dass Absturz-Berichte automatisch an Microsoft gesendet werden. Microsoft bittet explizit darum, den Editor nicht herunterzuladen, wenn man damit nicht einverstanden ist.

Ein Ausblick auf die Zukunft von Visual Studio Code

Den Funktionsumfang möchte Microsoft noch deutlich erweitern. Angedacht ist die Erweiterbarkeit durch Dritte. Hier möchte Microsoft wohl einen ähnlichen Weg beschreiten, wie die Macher von Atom oder Sublime Text 2. Jedoch soll Visual Studio Code stets ein leichter Editor für Web- und Cloud-Anwendungen bleiben, und keine aufgeblasene Entwicklungsumgebung werden. Das Potential zu einem vielgenutzten und beliebten Code-Editor hat Visual Studio Code. Die Zukunft wird zeigen, wie beliebt der Editor werden kann.

Das Video zu Visual Studio Code

Fazit

Microsofts Visual Studio Code macht einen recht interessanten Eindruck, kann mich aber zum jetzigen Zeitpunkt nicht zum Wechsel veranlassen. Da der Code-Editor sich in einer frühen Entwicklungsphase befindet, kann noch viel geschehen. Gerade die zukünftige Möglichkeit der Erweiterung durch Dritte kann recht interessant werden. Meine Empfehlung ist, den Editor nicht aus den Augen zu verlieren.

Links zum Beitrag

(dpe)

Kategorien
JavaScript & jQuery Programmierung

JavaScript: mit nativen Promises auf Callback-Verschachtelungen verzichten

Viele JavaScript-Frameworks wie jQuery und AngularJS kennen sogenannte Promises. Sie ermöglichen es, das Ergebnis asynchroner Aufrufe festzustellen und auf jenes Ergebnis zuzugreifen. Dabei lassen sich mehrere asynchrone Aufrufe „in Reihe schalten“. So wird erreicht, dass ein Aufruf erst gestartet wird, wenn ein anderer Aufruf bereits erfolgreich abgeschlossen wurde. Mittlerweile gibt es Promises auch als natives JavaScript-Objekt. So kann es ohne zusätzliche Frameworks und Bibliotheken eingesetzt werden.

JavaScript Promises

Wozu braucht man Promises?

Gerade in komplexen Webanwendungen kommt man ganz oft nicht umhin, per Events und Callbacks festzustellen, ob eine Operation erfolgreich abgeschlossen werden konnte – beispielsweise, wenn man Inhalte per „XMLHttpRequest()“ lädt und diese anschließend weiterverarbeiten will. Mit dem „load“-Event lässt sich hier über eine Callback-Funktion feststellen, wie der aktuelle Status des „XMLHttpRequest()“-Aufrufs ist.

function bild_laden(url) {
  var datei = new XMLHttpRequest();
  datei.open("GET", url);
  datei.addEventListener("load", function() {
    if (this.status == 200) {
      console.log(url + " geladen.");
    } else {
      console.log(url + "nicht geladen.");
    }
  }, false);
  datei.send();
}

bild_laden("bild.jpg");

Das simple Beispiel zeigt, wie Callbacks funktionieren. Das „load“-Event ruft eine Funktion auf, sobald der XMLHttpRequest()“-Aufruf erfolgreich war oder gescheitert ist. Der Status 200 im Beispiel wird ausgegeben, wenn das Laden erfolgreich war. Schwierig wird es allerdings, wenn beispielsweise eine zweite Datei geladen werden soll – und zwar, nachdem die erste geladen wurde.

bild_laden("bild1.jpg");
bild_laden("bild2.jpg");

Man kann natürlich die Funktion zweimal aufrufen und die beiden zu ladenden Dateinamen übergeben. Allerdings weiß man nie, welcher der beiden Requests als erster fertig ist. Bei den beiden Bildern im Beispiel dürfte es egal sein, welche Datei zuerst geladen wurde. Aber es gibt immer wieder Abläufe, bei denen man sicherstellen muss, dass bestimmte Inhalte bereits zur Verfügung stehen, bevor andere Inhalte geladen oder andere Operationen ausgeführt werden.

Jetzt kann man sich unterschiedlich behelfen, um festzustellen, ob eine Datei bereits geladen wurde. Man kann beispielsweise Events und die dazugehörigen Callback-Funktionen verschachteln.

function bild_laden(url1, url2) {
  var datei1 = new XMLHttpRequest();
  datei1.open("GET", url1);
  datei1.addEventListener("load", function() {
    if (this.status == 200) {
      console.log(url + " geladen.");
      var datei2 = new XMLHttpRequest();
      datei2.open("GET", url2);
      datei2.addEventListener("load", function() {
        if (this.status == 200) {
          console.log(url + " geladen.");
        } else {
          console.log(url + " nicht geladen.");
        }
      }, false);
      datei2.send();
    } else {
      console.log(url + " nicht geladen.");
    }
  }, false);
  datei1.send();
}

bild_laden("bild.jpg", "bild.jpg");

Das zweite Beispiel zeigt, dass bereits die Verschachtelung zweier Callback-Funktionen die ganze Sache recht komplex macht. Zwar erreicht man, dass die zweite Datei erst geladen wird, nachdem die erste erfolgreich geladen wurde. Kommen allerdings noch weitere Aufrufe dazu, die vom Erfolg anderer Aufrufe abhängig gemacht werden sollen, wird es für Programmierer oft sehr unübersichtlich. Nicht ohne Grund nennt man diese Problematik auch „Pyramid of Doom“.

Mit Promises gibt es eine wesentlich elegantere Möglichkeit, den Erfolg verschiedener Operationen festzustellen. Statt verschachtelter Callback-Funktionen wird der Erfolg beziehungsweise Misserfolg über ein sogenanntes Promise-Objekt festgestellt. Dabei haben Promises noch weitere Vorteile gegenüber einfacher Callbacks, die an späterer Stelle noch vorgestellt werden.

Neuen Promise anlegen

Um mit Promises zu arbeiten, muss zunächst ein neues Promise-Objekt angelegt werden. Diesem wird eine Funktion zugewiesen, die zwei Werte zurückgibt:

Der erste Wert – „Resolve“ genannt – wird zurückgegeben, wenn der Promise erfolgreich war, der zweite Wert – „Reject“ genannt –, wenn der Promise nicht erfolgreich war.

function bild_laden(url) {
  return new Promise(function(erfolg, misserfolg) {
    var datei = new XMLHttpRequest();
    datei.open("GET", url);
    datei.addEventListener("load", function() {
      if (this.status == 200) {
        erfolg(url + " geladen.");
      } else {
        misserfolg(url + " nicht geladen.");
      }
    }, false);
    datei.send();
  });
}

Im Beispiel wird der Funktion „bild_laden()“ per „return“ ein neues Promise-Objekt hinzugefügt. Das „return“ sorgt dafür, dass die Funktion das Ergebnis des Promises zurückgibt – also die Werte für „Resolve“ beziehungsweise „Reject“. Das Promise-Objekt enthält wiederum eine Funktion, die per „XMLHttpRequest()“ eine Datei lädt. Im Grunde wird dasselbe gemacht wie im ersten Beispiel. Auch hier wird per Callback-Funktion über das „load“-Event geprüft, ob die Datei geladen wurde oder nicht. Im Erfolgsfall wird dem „Resolve“ mit der Bezeichnung „erfolg“ ein Wert zugewiesen. Dieser Wert kann frei vergeben werden. Dem „Resolve“ kann auch der Inhalt der geladenen Datei („datei.response“) übergeben werden. So kann man später darauf zugreifen.

Der Wert für „Reject“ – im Beispiel „misserfolg“ – kann ebenfalls frei vergeben werden. Dieser wird meist verwendet, um eine Fehlermeldung auszugeben.

Der große Vorteil der Promises ist, dass das erfolgreiche Laden der Datei per „XMLHttpRequest()“ jenseits der Funktion „bild_laden()“ geprüft werden kann. Man muss Callback-Funktionen also nicht verschachteln. Dafür stehen die beiden Methoden „then()“ und „catch()“ zur Verfügung.

bild_laden("bild.jpg").then(
  function(erfolg) {
   console.log(erfolg);
  }
).catch(
  function(misserfolg) {
    console.log(misserfolg);
  }
);

Im Beispiel wird das Promise-Objekt beziehungsweise die Funktion „bild_laden()“ aufgerufen, um eine Datei zu laden. Die Methode „then()“ des Promise-Objektes wird dann ausgeführt, wenn der Promise erfolgreich war – die Datei also geladen wurde. Andernfalls wird die „catch()“-Methode ausgeführt. Während der „then()“-Methode der Inhalt von „Resolve“ – im Beispiel „erfolg“ – übergeben wird, erhält die „catch()“-Methode den Inhalt von „Reject“ – im Beispiel „misserfolg“. Über eine Funktion können die Inhalte der beiden übergebenen Variablen ausgegeben oder anderweitig verarbeitet werden. Im Beispiel werden die Werte einfach in die Konsole geschrieben.

Um mehrere Promise-Aufrufe „in Reihe zu schalten“, genügt es, mehrere „then()“-Methoden miteinander zu verketten. So wird erreicht, dass die erste „then()“-Methode erst dann aufgerufen wird, wenn der erste Promise erfolgreich war.

bild_laden("bild1.jpg").then(
  bild_laden("bild2.jpg")
).then(
  bild_laden("bild3.jpg")
).catch(
  function(misserfolg) {
    console.log(misserfolg);
  }
);

Das Beispiel zeigt, wie einfach Aufrufe verkettet werden können. Nachdem die Datei „bild1.jpg“ erfolgreich geladen wurde, wird per „then()“ die Datei „bild2.jpg“ geladen. Ist auch diese Datei geladen, wird eine dritte Datei geladen. Die „catch()“-Methode im Beispiel wird aufgerufen, wenn die erste Datei nicht geladen werden konnte – der erste Promise also erfolglos war.

Natürlich kann für jeden einzelnen Aufruf eine „catch()“-Methode ergänzt werden. So lässt sich jeder nicht erfolgreiche Aufruf der Funktion abfangen.

bild_laden("bild1.jpg").then(
  bild_laden("bild2.jpg")
).then(
  bild_laden("bild3.jpg").catch(
    function(misserfolg) {
      console.log(misserfolg);
    }
  )
).then(
  bild_laden("bild2.jpg").catch(
    function(misserfolg) {
      console.log(misserfolg);
    }
  )
).catch(
  function(misserfolg) {
    console.log(misserfolg);
  }
);

Dieses Beispiel zeigt, wie für jeden Aufruf der Funktion „bild_laden()“ eine entsprechende „catch()“-Methode ergänzt wurde. So entgeht einem kein erfolgloser Promise.

Ein Promise kann einen von drei Stati besitzen. Während geprüft wird, ob ein Promise erfüllt ist oder nicht, besitzt er den Status „pending“. Ist er erfüllt, hat er den Status „fulfilled“. Scheitert ein Promise, ist sein Status „rejected“. Der Status selbst lässt sich nicht abfragen, ist für das Verständnis von Promises aber nicht unwichtig.

Promises als Array übergeben und prüfen

Statt einzelne Funktionen per „then()“ aneinanderzuketten, gibt es auch eine einfachere Möglichkeit. Die Methode „all()“ erlaubt es, Funktionen beziehungsweise Promise-Objekte als Array zu übergeben und dieses Array als Ganzes zu prüfen.

Promise.all([bild_laden("bild1.jpg"), bild_laden("bild2.jpg")]).then(
  function (erfolg) {
    console.log(erfolg);
  }
);

Im Beispiel werden die einzelnen Aufrufe von „bild_laden()“ als Array der „all()“-Methode übergeben. Der Vorteil ist die wesentliche kürzere Auszeichnung. Allerdings hat man hierbei keine Möglichkeit, auf einzelne Misserfolge zu reagieren. Die „then()“-Methode wird nur dann ausgeführt, wenn alle Promises im Array erfüllt werden – also alle Dateien geladen sind. Sobald ein Promise im Array erfolglos war, gibt „all()“ für den gesamten Array den Status „rejected“ aus. Allerdings werden beim Status „fulfilled“ alle Rückgabewerte des Arrays („erfolg“) ausgegeben. Diese werden ebenfalls als Array bereitgestellt und im Beispiel in die Konsole geschrieben.

Schnellste Funktion wiedergeben

Neben der Methode „all()“ gibt es noch die Methode „race()“, bei der verschiedene Promises ebenfalls als Array übergeben werden. Statt alle Promises auszuführen und wiederzugeben, trifft das bei „race()“ nur auf den ersten erfolgreichen oder gescheiterten Promise zu.

Promise.race([bild_laden("bild1.jpg"), bild_laden("bild2.jpg")]).then(
  function (erfolg) {
    console.log(erfolg);
  }
);

Im Beispiel wird also nur für den ersten Promise, der erfolgreich oder nicht erfolgreich war, die Methode „then()“ aufgerufen. Relevant ist hierbei nur, welcher der Promises als erster einen Erfolg oder Misserfolg meldet.

Verkürzte Schreibweise für „catch()“

Auf die Auszeichnung der „catch()“-Methode kann auch verzichtet werden. Es gibt eine verkürzte Möglichkeit. Der „then()“-Methode können zwei Funktionen übergeben werden. Die erste der Funktionen wird dann beim Erfolg eines Promises ausgeführt, die zweite beim Misserfolg. Die zweite Funktion entspricht also der innerhalb der „catch()“-Methode.

bild_laden("bild.jpg").then(
  function(erfolg) {
    console.log(erfolg);
  }, function(misserfolg) {
    console.log(misserfolg);
  }
);

Die beiden Funktionen werden einfach per Komma voneinander getrennt. Will man nur eine Funktion für den Misserfolg definieren, genügt es, anstelle der ersten Funktion ein „undefined“ zu notieren.

Promises testen mit „resolve()“ und „reject()“

Mit den beiden Methoden „resolve()“ und „reject()“ kann man den Erfolg beziehungsweise Misserfolg eines Promises testen. Die „resolve()“-Methode gibt immer ein Promise-Objekt wieder, welches erfolgreich war – unabhängig davon, ob es tatsächlich von Erfolg gekrönt war. Die „reject()“-Methode hingegen stuft ein Promise-Objekt immer als nicht erfolgreich ein. In beiden Fällen werden die jeweiligen Werte von „Resolve“ beziehungsweise „Reject“ an die Methoden übergeben.

Promise.reject(bild_laden("bild1.jpg")).catch(
  function(misserfolg) {
    console.log(misserfolg);
  }
);

Im Beispiel wird per „reject()“ dafür gesorgt, dass die Funktion beziehungsweise das Promise-Objekt „bild_laden()“ als nicht erfolgreich wiedergegeben wird. Da die „then()“-Methode nur im Erfolgsfall aufgerufen wird, muss sie nicht aufgeführt werden. Denn dieser wird bei der „reject()“-Methode nie eintreten. Daher genügt es, die „catch()“-Methode aufzurufen.

Browsersupport und Polyfills

Promises laufen unter Chrome ab Version 32, Firefox ab Version 29 und Opera ab Version 19. Beim Internet Explorer sind Promises in der Entwicklung und werden möglicherweise in der nächsten Verison unterstützt. Es gibt auch ein Polyfill, der Promises für ältere Browser nachbildet.

Neben dem nativen Promise-Objekt und den Implementierungen in verschiedenen Frameworks wie jQuery und AngularJS gibt es auch Standalone-Frameworks für Promises. Dazu zählen unter anderem „Q“ sowie „Promise.js“. Diese Frameworks sollte man nicht vernachlässigen, nur weil es jetzt eine native JavaScript-Möglichkeit für Promises gibt. Denn die Promise-Objekte der Frameworks haben teils umfangreichere Features als das, was JavaScript nativ derzeit anbietet. Wer sich also weiter mit Promises auseinandersetzen will, sollte „Q“, „Promise.js“ und den anderen Frameworks durchaus mal etwas Aufmerksamkeit schenken.

Um festzustellen, ob der Browser native Promises unterstützt, genügt übrigens eine einfache „if“-Abfrage.

if (window.Promise) {
  …
}

Links zum Beitrag

(dpe)

Kategorien
JavaScript & jQuery Programmierung Sonstige Programmiersprachen Webdesign

Textures.js: SVG-Texturen für jede Oberfläche

Das SVG-Format stellt eine Vielzahl an Möglichkeiten bereit, um komplexe grafische Inhalte umzusetzen. Auch Texturen lassen sich mit dem „<pattern>“-Element erstellen und auf Formen anwenden. Aber gerade bei einfachen und gängigen Texturen ist der Aufwand, diese selbst per SVG auszuzeichnen, im Verhältnis zum Ergebnis recht hoch. Daher stellt die JavaScript-Bibliothek „Texture.js“ solche Texturen, die weitestgehend nur aus Linien und Punkten bestehen, für SVG-Elemente zur Verfügung. Mit wenigen Zeilen JavaScript kann man dann die einzelnen Formen einer SVG-Grafik mit unterschiedlichen Texturen versehen.

TEXTURE.JS

„Textures.js“ basiert auf „D3.js“

Da „Textures.js“ auf der JavaScript-Bibliothek „D3.js“ aufbaut, muss diese zusammen mit „Textures.js“ im HTML-Dokument eingebunden werden.

„D3.js“ hilft bei der Visualisierung von Daten verschiedenster Art. Man kann damit HTML- oder SVG-Elemente auswählen und nach bestimmten Vorgaben gestalten.

„D3.js“ sorgt im Zusammenspiel mit „Textures.js“ dafür, einzelne Formen innerhalb einer SVG-Grafik auszuwählen. Diese erhalten schließlich per „Textures.js“ ein Muster.

texturesjs

SVG-Grafik erstellen und mit Textur versehen

Zunächst einmal muss eine SVG-Grafik her. Diese wird im HTML-Dokument eingebettet und lässt sich fast nach Belieben gestalten. Nur eine Füllung für die Form darf nicht angegeben werden, da diese später per „Textures.js“ vergeben wird. Gibt man eine Füllung vor, wird diese später mit der Textur nicht überschrieben.

<svg width="225" height="150" id="grafik">
  <circle cx="75" cy="75" r="75" id="kreis1"></circle>
  <circle cx="150" cy="75" r="75" id="kreis2"></circle>
</svg>

Im Beispiel werden zwei einfache Kreise ausgezeichnet. Sowohl das „<svg>“- Element als auch die „<circle>“-Elemente erhalten eine ID, um sie später per „D3.js“ ansprechen zu können.

Das Prinzip von „Textures.js“ ist einfach erklärt. Die Bibliothek stellt per JavaScript eine Reihe unterschiedlicher Texturen bereit. Diese werden einem SVG-Element hinzugefügt. Dies geschieht, indem „Textures.js“ im SVG-Element für jedes Muster ein eigenes „<pattern>“-Element anlegt.

var svg = d3.select("#grafik");
var textur1 = textures.lines();
var textur2 = textures.circles();

svg.call(textur1);
svg.call(textur2);

Im Beispiel wird per „d3.select()“ zunächst die SVG-Grafik ausgewählt. Anschließend werden zwei Texturen erstellt. Im Beispiel fällt die Wahl auf die beiden Grundtexturen „lines()“ und „circles()“. Per „call()“ werden die Texturen dem SVG-Element hinzugefügt. Ab diesem Moment stehen die Muster innerhalb der Grafik bereit.

texturesjs_einfache-muster

Einfache Muster

Im letzten Schritt müssen die Texturen noch den beiden Kreisen zugeordnet werden.

var kreis1 = d3.select("kreis1");
var kreis2 = d3.select("kreis");

kreis1.style("fill", textur1.url());
kreis2.style("fill", textur2.url());

Auch hierbei werden die Kreise erst per „d3.select()“ ausgewählt. Anschließend weisen wir den Elementen per „style()“ die Eigenschaft „fill“ mit den URLs der beiden Muster zu. Die URLs des Musters ist jeweils eine ID, die von „Textures.js“ vergeben wird.

Texturen anpassen

„Textures.js“ kennt drei Grundformen: Linien, Kreise und Pfade. Dabei lässt sich jede Grundform anpassen. Bei Linien kann die Stärke, der Abstand und die Ausrichtung angegeben werden. Für jede Eigenschaft, die angepasst werden soll, gibt es eine Methode, die einfach an „lines()“ angehängt wird.

textures.lines().stroke("green").strokeWidth(1).size(5).orientation("2/8");

Im Beispiel wird per „stroke()“ die Farbe der Linien definiert. Per „strokeWidth()“ wird die Linienstärke und per „size()“ der Abstand der Linien zueinander festgelegt. Der Wert für „orientation()“ gibt die Ausrichtung der Linien an. Neben Werten wie „horizontal“, „vertical“ und „diagonal“ gibt es auch die Möglichkeit, die Ausrichtung als Achtelbruch auszugeben. „2/8“ entspricht hierbei einer diagonalen Ausrichtung, „4/8“ einer horizontalen Ausrichtung und „8/8“ einer vertikalen Ausrichtung.

texturesjs_angepasste-muster

Individuell angepasste Muster

Bei Kreisen gibt es keine Ausrichtung. Dafür besteht zusätzlich die Möglichkeit, eine Füllfarbe anzugeben.

textures.circles().fill("orange").radius(5).size(15);

Außerdem wird die Größe der Kreise per „radius()“ definiert. Mit der zusätzlichen Eigenschaft „complement()“ sorgen wir dafür, dass die Kreise nicht in Reihen und Spalten neben- und untereinander dargestellt werden, sondern jeweils versetzt.

texturesjs_angepasste-muster-versetzt

In Reih und Glied angeordenete Kreise sowie versetzt angeordnete Kreise

Mit den Pfadtexturen stehen einem noch eine Reihe weitere Muster zur Verfügung, die komplexer sind, als die einfachen Linien- und Kreismuster. Insgesamt sieben Pfadmuster – zum Beispiel Kreuze, Hexagone und Wellen – stehen zur Auswahl.

textures.paths().d("waves").stroke("blue");

Über die Eigenschaft „d()“ legen wir die Art des Musters fest. Anschließend lassen sich Farbe und Linienstärke, wie auch bei den anderen Mustern, festlegen.

texturesjs_weitere-muster

Pfadtexturen

Auch individuelle Muster möglich

Wem das Angebot an Texturen nicht ausreicht, der kann mit „Textures.js“ auch eigene Muster auf der Grundlage der Pfadtexturen erstellen. Dazu wird „d()“ eine Funktion übergeben, welche die Form des Musters beschreibt.

textures.paths().d(function(s) {
  return "M …";
}).stroke("blue");

Per „return“ werden innerhalb der Funktion die Koordinaten für die „d“-Eigenschaft eines SVG-Pfades ausgegeben.

Fazit und Link zum Beitrag

Mit „Textures.js“ stehen einem viele Muster zur Verfügung, die sich schnell SVG-Formen zuordnen lassen. Die Anwendung ist einfach und Anpassungen sind schnell erledigt. Textures.js steht unter der MIT-Lizenz zur kostenlosen Verwendung für private und kommerzielle Zwecke bereit. D3.js steht unter der ähnlich liberalen BSD-Lizenz.

(dpe)

Kategorien
JavaScript & jQuery Webdesign

Awesomplete: Schnelles Autocomplete-Widget, individuell gestaltbar

Dass einem bei einer Sucheingabe per Dropdown eine Liste mit Autocomplete-Vorschlägen angezeigt wird, ist keine Seltenheit. Dank des HTML5-Datalist-Elements lassen sich sehr einfach und ohne JavaScript solche Autocomplete-Listen erstellen. Die Möglichkeiten, diese Listen zu konfigurieren, sind jedoch beschränkt. So lässt sich mit dem Element beispielsweise nicht definieren, ab wie vielen Eingabezeichen die Liste mit den Vorschlägen dargestellt werden soll. Auch gibt es keine Möglichkeit, Vorschläge aus anderen Listen – beispielsweise aus einer einfachen „<ul>“-Liste – zu verwenden. Die JavaScript-Bibliothek „Awesomplete“ schafft genau diese Möglichkeiten, um Autocomplete-Listen flexibler und individueller zu machen.

awesomplete-teaser

Sehr klein und schnell eingebunden

Die JavaScript-Datei ist in der komprimierten Fassung keine fünf Kilobyte groß. Ist sie im HTML-Kopf eingebunden, muss dem „<input>“-Element, welches „Awesomplete“ verwenden soll, nur noch die Klasse „awesomplete“ zugewiesen werden. Anschließend hat man mehrere Möglichkeiten, wie man das Widget verwenden möchte. Zunächst kann man beim „<datalist>“-Element bleiben, um Vorschläge für die Autovervollständigung zu definieren.

awesomplete

<input type="text" list="suchbegriffe" class="awesomplete" />

<datalist id="suchbegriffe">
  <option>Webdesign</option>
  <option>Webentwicklung</option>
  <option>…</option>
</datalist>

Im Beispiel wird eine klassische Dataliste erstellt, welche wir über die ID einem Eingabefeld zuweisen. Normalerweise würde bei entsprechender Eingabe ins Suchfeld eine Standard-Dropdown-Liste mit den Vorschlägen erscheinen. „Awesomplete“ hingegen stellt die Suchvorschläge als gestaltbare „<ul>“-Liste dar. Hier hat man mit CSS also die Möglichkeit, das Aussehen der Liste individuell anzupassen. Das Widget sorgt dafür, dass sowohl das „<input>“-Element als auch die „<ul>“-Liste in einem „<div>“-Container mit der Klasse „awesomplete“ platziert sind. Über den Container und die Klasse kann man nun die Gestaltung von Eingabefeld und Liste individuell festlegen. „Awesomplete“ liefert auch gleich ein eigenes Stylesheet mit, welches die Liste in Form eines Tooltipps darstellt.

awesomplete_vergleich
Vergleich zwischen Standardliste (links) und „Awesomplete“-Liste (rechts)

Alternative Listen verwenden

Während per HTML nur das „<datalist>“-Element für die Autocomplete-Funktion in Frage kommt, ermöglicht „Awesomplete“ auch alternative Listen. Will man beispielsweise eine bestehende Liste über ein Eingabefeld durchsuchbar machen, kann man diese Liste einem Eingabefeld zuordnen.

<input type="text" data-list="#suchbegriffe" class="awesomplete" />

<ul id="suchbegriffe">
  <li>Webdesign</li>
  <li>Webentwicklung</li>
  <li>…</li>
</ul>

Im Beispiel wird eine einfache „<ul>“-Liste einem Eingabefeld zugeweisen. Statt des Attributs „list“ wird hier jedoch das Data-Attribut „data-list“ verwendet, um die Liste zuzuweisen. Außerdem muss der ID der zu verwendenden Liste eine Raute vorangestellt werden. Das Beispiel funktioniert dann genau wie die Variante mit dem „<datalist>“-Element.

Als dritte Möglichkeit erlaubt es „Awesomplete“ auch, die Vorschläge für die Autovervollständigung per Data-Attribut direkt im „<input>“-Element unterzubringen. Dazu werden einfach alle Begriffe ins Attribut „data-list“ geschrieben.

<input type="text" data-list="Webdesign, Webentwicklung, …" class="awesomplete" />

Individuelle Konfiguration

Eine weitere Stärke von „Awesomplete“ sind die verschiedenen Einstellungsmöglichkeiten. So lässt sich beispielsweise festlegen, ab wie vielen eingegebenen Zeichen die Autovervollständigung anspringen soll. Normalerweise werden ab dem zweiten Zeichen Vorschläge gemacht.

new Awesomplete(document.getElementsByTagName("input")[0], {
  minChars: 1,
  maxItems: 1,
  autoFirst: true
});

Über den Konstruktor „Awesomplete()“ nehmen wir alle Einstellungen vor. Erwartet werden zwei Parameter. Der erste gibt das Element an, auf welches die Einstellungen angewendet werden sollen. Im Beispiel ist es das erste „<input>“-Element innerhalb eines HTML-Dokumentes. Anschließend werden alle Konfigurationsparameter über ein Objektliteral angegeben.

Der Parameter „minChars“ gibt die Anzahl der Zeichen an, die mindestens eingegeben werden müssen, damit eine Vorschlagsliste erscheint. Über „maxItems“ wird die maximale Anzahl der angezeigten Einträge definiert.

Über den Parameter „autoFirst“ ist es möglich, das erste dargestellte Element automatisch auszuwählen. Dadurch erspart man sich einen Klick auf das erste Element, wenn man es ins Eingabefeld übernehmen möchte. Stattdessen genügt ein Return per Tastatur.

Per Events reagieren

Um auch auf Interaktionen mit der Vorschlagsliste reagieren zu können, gibt es eigene Events, die beispielsweise ausgelöst werden, wenn ein Element aus der Liste ausgewählt wurde. Die Events lassen sich per „addEventListener()“ anwenden und unterscheiden sich somit nicht von nativen Ereignissen.

document.getElementsByTagName("input")[0].addEventListener("awesomplete-select", function() {
  alert("Sie haben einen Suchbegriff ausgewählt.");
}, false);

Im Beispiel wird ein Alert ausgegeben, wenn ein Begriff aus der Liste ausgewählt wurde. Es stehen mehrere Events zur Verfügung, die alle mit „awesomplete-“ eingeleitet werden.

Fazit und Link zum Beitrag

Wem die Standardmöglichkeiten für Autocomplete-Listen nicht ausreichen, findet bei „Awesomplete“ eine große Fülle an individuellen Gestaltungs- und Konfigurationsmöglichkeiten. Das Widget ist gut dokumentiert und steht unter der verbreiteten MIT-Lizenz, die eine kostenfreie Nutzung erlaubt.

(dpe)

Kategorien
HTML/CSS JavaScript & jQuery Webdesign

Circulus.SVG – Kreismenüs mit SVG zum Zusammenklicken

Das SVG-Format kann deutlich mehr als vektorbasierte Grafiken bereitzustellen. So lassen sich auch ungewöhnliche Navigationen realisieren, die sich von den sonstigen Menüs sehr schön abheben. Mit Circulus.SVG ist es beispielsweise möglich, eine Navigation in Form eines Kreises oder auch Halbkreises zu gestalten. Dabei lässt sich das Aussehen des Kreises und die Anzahl der Menüpunkte einfach über ein Konfigurationsmenü zusammenstellen.

circulussvg-teaser

Grundlayout für Kreismenü erstellen

Bei vielen SVG-Frameworks muss man sich das Aussehen mühsam per JavaScript-Parameter erarbeiten. Circulus.SVG stellt eine grafische Oberfläche mit Konfigurationsmenü zur Verfügung. Darüber baut man sich das Grundlayout für ein Kreismenü bequem und einfach zusammen. So kann man sein Menü als Ganz- oder Halbkreis, sowie als Pizza (ohne Loch in der Mitte des Kreises) oder Kuchen (mit Loch in der Mitte des Kreise) darstellen.

circulussvg

Über verschiedene Schieberegler werden die Größe des Kreises und beim Kuchen-Modus die Größe des inneren Kreises festgelegt. Die Position und Größe der Menü-Icons lässt sich auf diese Weise ebenfalls einstellen. Auf Wunsch wird ein Abstand zwischen den Menüpunkten beziehungsweise Kreissegmenten angegeben. In der Mitte des Kreismenüs befindet sich ein sogenannter Trigger, der später mit einer Funktion und einem Text versehen werden kann. Darüber ist das Menü beispielsweise minimier- und wieder vergrößerbar.

circulussvg-menue
Konfiguration eines Kreismenüs

Ebenfalls wichtig ist die Angabe der Anzahl der Menüpunkte. Sind alle Angaben gemacht, lädt man die SVG-Datei mit dem Grundlayout herunter.

Aufbau der SVG-Datei

Die heruntergeladene SVG-Datei besitzt einen Style-Bereich, über den das Aussehen der einzelnen Menüpunkte beziehungsweise Kreissegmente per CSS ausgezeichnet wird. Innerhalb der Gruppe (<g>) mit der ID symbolsContainer befinden sich Platzhalter für die Menü-Icons beziehungsweise die Beschriftung der einzelnen Menüpunkte. In der Gruppe mit der ID itemsContainer befinden sich die einzelnen Menüpunkte samt Links.

Die letzte Gruppe mit der ID trigger beinhaltet einen Kreis, der im Mittelpunkt des Menüs platziert ist und mit einer Funktion versehen werden kann.

SVG-Datei anpassen

Innerhalb der Gruppe itemsContainer befinden sich die einzelnen Kreissegmente. Jedes Kreissegment besteht aus einem <a>-Element, dessen Kind ein <path>-Element ist, welches die jeweilige Form des Segmentes darstellt. Über das href-Attribut der <a>-Elemente werden die Links übergeben, die beim Klick darauf aufgerufen werden sollen. Zusätzlich kann per title-Attribut ein Tooltip definiet werden. Standardmäßig werden die Links per target-Attribut im Elternfenster aufgerufen. Alternativ ist beispielsweise auch ein Aufruf in einem neuen Fenster beziehungsweise Tab möglich.

<a class="item" id="item-2" xlink:href="http://www.drweb.de/" xlink:title="Dr. Web" xlink:target="_blank" …>
  <path fill="none" stroke="#111" stroke-width="1" class="sector" …></path>
  <use xlink:href="#icon-2" …></use>
</a>

Außerdem haben die <a>-Elemente als Kind noch jeweils ein <use>-Element, über welches das jeweilige Icon für den Menüpunkt eingebunden wird. Die <a>-Elemente besitzen alle die Klasse item, die <path>-Elemente die Klasse sector. Im Style-Bereich lässt sich das Aussehen über diese Klassen entsprechend anpassen.

.item .sector {
  fill: red;
  stroke: none;
}

.item:hover sector {
  fill: green;
}

Im nächsten Schritt lassen sich eigene Icons im Menü integrieren. Die Icons werden in der Gruppe mit der ID symbolsContainer platziert. Für jeden Menüpunkt steht dort ein <symbol>-Element mit einer Platzhaltergrafik samt Text bereit. Die Platzhalter sind entsprechend im SVG-Quelltext markiert und lassen sich auf diese Weise leicht finden und ersetzen. So können eigene Formen integriert werden.

<symbol class="icon icon-" id="icon-1" viewBox="0 0 63 63">
  <!--Replace the contents of this symbol with the content of your icon-->
  …
</symbol>

Das Beispiel zeigt ein <symbol>-Element mit dem Platzhalter. Innerhalb des Elementes lassen sich eigene Formen beispielsweise als <path>– oder <polygon>-Elemente einfügen. Wer auf Icons verzichten will, kann auch einfach nur Text über das <text>-Element einfügen. Über die ID des <symbol>-Elementes wird das Icon dem <use>-Element eines Menüpunktes übergeben.

circulussvg-beispiel
Beispiel für ein Halbkreismenü

Menü mit JavaScript animieren

Bislang kommt das Menü ohne Animation aus. Allerdings besteht die Möglichkeit, das Kreismenü per JavaScript in Bewegung zu versetzen. Über den Trigger kann eine Funktion aufgerufen werden, die das Menü verkleinert und wieder vergrößert.

In Kombination mit dem SVG-Framework Snap.SVG lassen sich solche Funktionen recht einfach realisieren. Auf der Projektwebsite stehen mehrere Beispiele zur Verfügung, die solche Ein- und Ausklapp-Animationen auf ein Kreismenü anwenden. Diese kann man einfach ins eigene Projekt übernehmen.

Fazit

Mit Circulus.SVG lassen sich sehr schöne und ungewöhnliche Navigationen realisieren. Moderne Browser haben mit dem SVG-Format ohnehin keine Probleme. Der Internet Explorer macht ab Version 9 mit. Circulus.SVG stammt aus der Feder der Designerin Sara Soueidan aus dem Libanon, die treue Leser unserer Magazinfamilie vielleicht schon als Autorin des Smashing Magazine kennen.

(dpe)

Kategorien
Design JavaScript & jQuery Responsive Design Webdesign

Flickity: Schicke Galerien auf allen Geräten – responsiv und mit Gestensteuerung

Es gibt zahlreiche Lösungen, um Galerien per JavaScript zu realisieren. Mal überzeugt die Bedienung nicht, mal ist der Funktionsumfang eher bescheiden. „Flickity“ hingegen ist ein zeitgemäßes JavaScript-Framework für Galerien, welches nicht nur am Desktop funktioniert, sondern auch für Mobilgeräte bestens geeignet ist. Die Galerie ist responsiv und lässt sich sowohl per Maus als auch per Gesten bedienen – bei Bedarf auch per Tastatur. Dank CSS3 kann man sich zudem schnell und animiert durch die Galerie bewegen.

flickity-teaser

Fix eingebunden und konfiguriert

Wer sich nicht erst durch die Dokumentation lesen will, kann „Flickity“ ohne zusätzliche Konfiguration schnell ins eigene Projekt einbinden. Neben einer JavaScript-Datei für die Funktionalität muss eine Stylesheet-Datei für das Aussehen und die animierten Übergänge im HTML-Kopf eingebunden werden. Anschließend lässt sich per HTML die eigentliche Galerie auszeichnen.

Dazu wird ein Container-Element bestimmt, welches alle Galerie-Elemente umschließt. Dieses erhält die Klassen „gallery“ und „js-flickity“. Dabei kann es sich um ein „<div>“-Element oder ein beliebiges anderes Blockelement handeln – zum Beispiel auch „<figure>“. Die einzelnen Galerie-Elemente erhalten die Klasse „gallery-cell“. Auch hierbei kann es sich um ein „<div>“-Element handeln, welches beispielsweise Bilder oder andere Inhalte umschließt. Es kann aber auch direkt ein „<img>“-Element verwendet werden. Hier ist man sehr flexibel bei der Wahl der Elemente.

<figure class="gallery js-flickity">
  <img src="1.jpg" class="gallery-cell" />
  <img src="2.jpg" class="gallery-cell" />
  <img src="3.jpg" class="gallery-cell" />
  …
</figure>

Im Beispiel werden ein „<figure>“-Element als Container und drei „<img>“-Elemente als Inhalte für die Galerie definiert. Mehr ist schon gar nicht zu tun, um mit „Flickity“ eine responsive Galerie zu erstellen. Per JavaScript werden verschiedene Buttons ergänzt. Zum einen gibt es zwei Pfeil-Buttons, um jeweils ein Bild vor- und zurückspringen zu können. Außerdem gibt es die Möglichkeit, jedes einzelne Bild der Galerie direkt anzusteuern – per Punkte-Navigation am unteren Rand. Darüber hinaus kann man sich per Drag-Funktion der Maus durch die Galerie bewegen. Auf Mobilgeräten ist die Steuerung per Geste möglich.

flickity_galerie_zentriert
Standardaussehen der Galerie, bei dem das ausgewählte Bild zentriert dargestellt wird

Die Pfeil-Buttons werden per „<button>“-Element ausgzeichnet, die Punkte-Navigation als Liste per „<ul>“- und „<li>“-Elemente. Die Pfeile der Buttons sind als SVG-Grafiken hinterlegt. Die einzelnen Menüelemente der Punkte-Navigation sind direkt per CSS gestaltet.

Das Stylesheet sorgt dafür, dass der Wechsel der Bilder per Animation erfolgt. Wird der Galerie keine feste Breite zugewiesen, nimmt sie immer die Breite des Elternelementes ein. Die Größe der einzelnen Bilder wird dabei nicht verändert. Je nach Breite sind Galerie-Elemente neben dem jeweils aktiven Element im Anschnitt sichtbar.

Verändert man die Breite des Browserfensters passt sich die Galerie automatisch der neuen Breite an. Auf Mobilgeräten wird somit auch bei veränderter Bildschirmorientierung die Galerie angepasst.

Auch wenn Bilder ein klassischer Anwendungsfall für eine Galerie sind, ist „Flickity“ nicht auf Bilder reduziert. Wie bereits erwähnt, lassen sich beliebige Elemente per „gallery-cell“ als Galerie-Element auszeichnen. Darin können sich beliebige Inhalte wie Texte und Text-Bild-Kombinationen befinden.

Dank zahlreicher Einstellungen sehr flexibel

„Flickity“ hat zahlreiche Einstellungsmöglichkeiten und kann daher sehr individuell angepasst werden. Die einzelnen Konfigurationsparameter werden dabei über das Data-Attribut „data-flickity-options“ direkt im Container-Element der Galerie definiert. Dabei werden diese als JSON-Objekt übergeben. So lassen sich beispielsweise die beiden Menüs – Vor- und Zurück-Buttons sowie die Punkte-Navigation – ausschalten.

<figure class="gallery js-flickity" data-flickity-options='{"prevNextButtons": false, "pageDots": false}'>
  …
</figure>

Da innerhalb des JSON-Objektes die Parameter zwingend in doppelten Anführungszeichen stehen müssen, muss das JSON-Objekt selbst in einfachen Anführungszeichen dem Data-Attribut zugewiesen werden.

Im Beispiel werden per „prevNextButtons“ und „pageDots“ alle Menü-Elemente entfernt. Eine Navigation ist dann nur noch per Maus beziehungsweise Geste möglich.

Auch das Aussehen der Galerie-Elemente lässt sich beeinflussen. So kann die Ausrichtung der einzelnen Elemente definiert werden. Per „cellAlign“ ist es möglich, ein Galerie-Element links- oder rechtsbündig sowie zentriert darzustellen.

<figure class="gallery js-flickity" data-flickity-options='{"cellAlign": "left"}'>
  …
</figure>

flickity_galerie_links
Galerie, bei dem das ausgewählte Bild linksbündig dargestellt wird

Über den Parameter „contain“ ist es möglich, die Galerie-Elemente so darzustellen, dass immer die gesamte Galeriebreite ausgefüllt wird. Das erste Galerie-Element würde dann immer am linken Rand, das letzte am rechten Rand dargestellt. Es entsteht also kein leerer Bereich.

<figure class="gallery js-flickity" data-flickity-options='{"contain": true}'>
  …
</figure>

flickity_galerie_contain
Zwei Galerien mit linksbündiger Darstellung: links mit gesetztem „contain“-Parameter, rechts ohne

Hervorzuheben ist darüber hinaus noch die Möglichkeit, freies Scrollen zu erlauben. Hierbei wird per „freeScroll“ dafür gesorgt, dass das jeweils aktive Bild beim Loslassen nicht automatisch in die definierte Ausrichtung gebracht wird. Außerdem kann man per „wrapAround“ ein Endlos-Scrolling zu realisieren. Hierbei wird nach dem letzten Galerie-Element wieder das erste platziert und vor dem ersten das letzte.

<figure class="gallery js-flickity" data-flickity-options='{"freeScroll": true, "wrapAround": true}'>
  …
</figure>

Mit dem „autoPlay“-Parameter sorgt man für einen automatischen Wechsel der einzelnen Bilder der Galerie. Angegeben wird eine Dauer für die Anzeige pro Bild. Die Auto-Play-Funktion wird deaktiviert, sobald die Galerie manuell bedient wird.

<figure class="gallery js-flickity" data-flickity-options='{"autoPlay": 1500}'>
  …
</figure>

Im Beispiel erfolgt ein automatischer Bildwechsel all eineinhalb Sekunden.

Wer mehrere Galerien verwendet und diese zentral einstellen möchte, kann dies tun. Hierzu ist es allerdings notwendig, jQuery oder Vanilla JS eingebunden zu haben.

$(".gallery").flickity({
  cellAlign: "right",
  contain: true
});

Im Beispiel werden Einstellungen für alle Galerien mit der Klasse „gallery“ vorgenommen.

Die hier vorgestellten Parameter stellen nur einen Teil der Möglichkeiten vor, mit denen „Flickity“ konfiguriert werden kann. Wer es noch individueller mag, kann sich anhand der „Flickity“-API beispielsweise eine individuelle Navigation bauen oder dynamisch Elemente der Galerie hinzufügen und sie daraus löschen. Über die API stehen auch eine Reihe von Events zur Verfügung, mit denen auf Interaktionen mit der Galerie reagiert werden.

Fazit und Nutzung

„Flickity“ ist ein sehr durchdachtes Galerie-Framework. Die Galerien erinnern von der Bedienung sehr an das, was man von nativen Apps für Mobilgeräte gewohnt ist. Daher ist die Bedienung sehr intuitiv. Dass es zunehmend wichtig geworden ist, auch auf Mobilgeräten entsprechend bequem und anspruchsvoll Bilder und Ähnliches zu präsentieren, dürfte nicht hervorgehoben werden müssen. „Flickity“ erfüllt all dies.

Die Konfiguration von „Flickity“ ist zudem spielend einfach. Die einzelnen Parameter werden mit Beispielen in der Dokumentation gut vorgestellt. Außerdem gibt es für jedes Beispiel einen bearbeitbaren Quelltext auf CodePen, wo man die jeweilige Einstellung direkt selbst ausprobieren und verändern kann.

„Flickity“ läuft auf allen modernen Browsern. Der Internet Explorer ist ab Version 8 dabei, Android-Browser ab Version 2.3 und iOS-Browser ab Version 5.

Allerdings ist die Nutzung von „Flickity“ nur für Open-Source-Projekte kostenlos. Alle anderen müssen für eine Einzellizenz 25 Dollar bezahlen. Die Lizenz gilt jedoch pro Entwickler und nicht pro Website. Das heißt, man kann das Framework in mehreren Projekten einsetzen. Es gibt auch eine Lizenz für bis zu acht Entwickler für 110 Dollar sowie eine für beliebig viele Entwickler, die dann für 290 Dollar zu haben ist.

Link zum Beitrag

(dpe)

Kategorien
JavaScript & jQuery Programmierung Webdesign

Ich dreh am Rad: Wheelnav.js erlaubt kreisrunde Navigationsmenüs

Eine Navigation muss nicht immer horizontal oder vertikal angeordnet sein. Sie kann sich durchaus auch mal im Kreis drehen. Besonders einfach geht das mit der Javascript-Bibliothek Wheelnav.js. Diese erlaubt es, Menüs kreisförmig anzuordnen. Auswahlen tätigt man durch Drehen. Wheelnav.js basiert auf Raphaël.js, welches das Zeichnen von SVG-Grafiken per Javascript ermöglicht.

wheelnavjs-teaser

Kickstart: Bibliotheken einbinden und Elemente auszeichnen

Bevor es losgeht, müssen Wheelnav.js und Raphaël.js in ein HTML-Dokument eingebunden werden. Optional kann auch die kostenlose Icon-Sammlung von Raphaël.js mit Verwendung finden, falls man die Navigationselemente nicht ausschließlich als Text auszeichnen möchte. So hat man schnellen Zugriff auf über 250 Icons.

wheelnavjs

Anschließend wird ein Container-Element erstellt, welches später über dessen ID mit der kreisförmigen Navigation in Form eines SVG-Elementes zu füllen ist.

<div id="navigation"></div>

Die komplette Einrichtung der Navigation erfolgt über Wheelnav.js. Auch die einzelnen Menüpunkte werden über die Bibliothek ausgezeichnet. Der Nachteil dieser Lösung ist natürlich, dass ohne Javascript keine Navigation zur Verfügung steht. Hier bietet es sich an, zusätzlich eine HTML-basierte Navigation innerhalb des Containers zu platzieren – sollte es innerhalb des Menüs Links zu anderen Seiten geben. Wheelnav.js wird nämlich alles, was innerhalb des <div>-Elementes steht, entfernen.

Navigation erstellen und konfigurieren

Im nächsten Schritt wird die Navigation per Wheelnav.js erstellt. Dies erfolgt über den Aufruf von wheelnav(), wobei hier die ID des Container-Elements übergeben wird.

var nav_im_kreis = new wheelnav("navigation");

Anschließend stehen einem verschiedene Eigenschaften und Methoden zur Verfügung, mit denen das Aussehen, der Inhalt und die Funktionalität der Kreisnavigation festgelegt werden können.

Über slicePathFunction definiert man zunächst das Aussehen des Menüs. Hier muss man sich für eine der verfügbaren Formen für das Menü entscheiden. Beim klassischen PieSlice wird die Navigation kreisförmig wie bei einem Tortendiagramm dargestellt. Jeder Menüpunkt ist dann ein Segment dieses Diagramms. Bei DonutSlice ist zusätzlich eine runde Aussparung in der Kreismitte vorhanden. Alternativ kann man die einzelnen Menüpunkte auch per MenuSliceWithoutLine jeweils als einzelne Kreise darstellen, die wiederum kreisförmig zueinander angeordnet sind.

wheelnavjs_basistypen
Die acht Basistypen

Insgesamt stehen acht verschiedene Basistypen zur Auswahl. Darüber hinaus gibt es noch einige spezifische Formen sowie die Möglichkeit, Pfade für das Aussehen der Navigation selbst zu erstellen. Diese werden als Funktion bereitgestellt und können schon mal recht komplex ausfallen.

nav_im_kreis.slicePathFunction = slicePath().Pie;

Im Beispiel definieren wir ein einfaches kreisförmiges Menü. createWheel() zeichnet die Navigation letztendlich als SVG-Grafik ins <div>-Element.

nav_im_kreis.createWheel();

Sind keine weitere Angaben gemacht, enthält die Navigation vier Menüelemente, die automatisch eingefärbt und mit einem Titel  im Stile von title-* versehen werden.

Menüelemente definieren

Aussehen und Beschriftung der einzelnen Menüelemente lassen sich natürlich frei definieren. Per initWheel() gibt man die Beschriftung der Elemente an. Die einzelnen Beschriftungstexte werden dabei als Objektliteral übergeben.

nav_im_kreis.initWheel(["Start", "Profil", "Kontakt"]);

Statt Texte zu verwenden, kann man auch die Icons von Raphaël.js an dieser Stelle verwenden. Auf der Website von Raphaël.js gibt es eine Übersicht aller Icons und ihrer Bezeichnungen.

nav_im_kreis.initWheel([icon.home, "Profil", "Kontakt"]);

Für die Farbe der Menüelemente stehen 13 vordefinierte Paletten zur Auswahl. Alternativ hat man die Möglichkeit, die Farben als Array selbst zu definieren. Idealerweise definiert man so viele Farben, wie Menüelemente vorhanden sind.

wheelnavjs_farbpaletten
Die vordefinierten Farbpaletten

Bei den vordefinierten Farbpaletten sind jeweils fünf bis acht Werte hinterlegt.

nav_im_kreis.colors = new Array("#4F346B", "#623491", "#9657D6");

Funktionen hinzufügen

Aussehen und Inhalt des Kreismenüs sind nun festgelegt. Per Klick auf eines der Elemente dreht sich der Kreis so, dass das jeweils ausgewählte Element rechts steht. Was sonst noch passieren soll, wenn man ein Element auswählt, lässt sich über Funktionen regeln, die den jeweiligen Menüelementen zugewiesen werden.

nav_im_kreis.navItems[0].navigateFunction = function () {
  alert("Startseite angeklickt.");
};

Über navItems[*] ist jeder einzelne Menüpunkt ansprechbar. Per navigateFunction übergibt man eine Funktion, die beim Klick auf den entsprechenden Menüpunkt aufgerufen wird. Im Beispiel geben wir einen Alert aus, wenn der erste Menüpunkt ausgewählt wird.

Animationen mit Wheelnav.js

Wie bereits erwähnt, dreht sich die Navigation bei jedem Klick jeweils so, dass das ausgewählte Menüelement jeweils auf 3 Uhr steht. Über navAngle kann dieser Winkel verändert werden, wobei 0 Grad den Standardwinkel darstellt.

nav_im_kreis.navAngle = 90;

Über animatetime und animateeffect hat man zudem die Möglichkeit, die Geschwindigkeit der Animation in Millisekunden sowie das Easing der Animation zu definieren. Hier stehen einem die Easing-Effekte von Raphaël.js zur Verfügung. Dazu zählen klassische Effekte wie ease-in und ease-out. Es gibt aber auch ganz spezielle Easing-Effekte wie elastic.

nav_im_kreis.animatetime = 5000;
nav_im_kreis.animateeffect = "elastic";

sliceSelectedTransformFunction erlaubt zudem, das jeweils aktive Menüelement über eine kleine Animation hervorzuheben. So lässt sich dieses Element im aktiven Zustand aus der Navigation herausbewegen, drehen oder auch vergrößern.

nav_im_kreis.sliceSelectedTransformFunction = sliceTransform().MoveMiddleTransform;

Im Beispiel wird per MoveMiddleTransform dafür gesorgt, dass sich aktive Elemente etwas aus der Mitte der Kreisnavigation herausbewegen.

wheelnavjs_hervorhebung
Drei Möglichkeiten der Hervorhebung aktiver Elemente

Fazit, Kosten und Lizenz

Die hier vorgestellten Möglichkeiten von Wheelnav.js zeigen nur einen kleinen Teil dessen, was möglich ist. Unter anderem erlaubt es die Bibliothek etwa, die Formen der Navigation komplett selbst festzulegen. Man ist also nicht auf die vorhandenen Vorgaben limitiert. Schön wäre es, wenn die Auszeichnung der Links per HTML möglich wäre und Wheelnav.js diese auslesen würde. Eine ausschließliche Auszeichnung per JavaScript, wie sie momentan der Stand der Entwicklung ist, ist nicht die optimale Lösung.

Dennoch ist die Bibliothek eine feine Sache, um außergewöhnliche und animierte Menüs erstellen zu können. Da die Ausgabe per SVG erfolgt und die Größe der Menüs einfach per CSS definiert wird, sind die Menüs auch responsiv problemlos einsetzbar. Sogar komplexe Menüs einschließlich Untermenüs können mit der Bibliothek realisiert werden. Die Möglichkeiten sind also sehr vielfältig.

wheelnavjs_untermenue
Menü mit Untermenü

Wheelnav.js steht unter MIT-Lizenz, ist somit privat und kommerziell frei einsetzbar, und kann über Github heruntergeladen werden. Auf der Website der Bibliothek besteht zudem die Möglichkeit, das Projekt mit einer Spende zu unterstützen.

Link zum Beitrag