Bernhard Häussner
Tags: Artikel mit dem Tag «Javascript» durchstöbern

Symmetrisch Zeichnen

17.12.2009, 10:43

Neben Symmetrie in der Natur bin ich auch begeistert von den Symmetrien, die der Computer erstellen kann. Und was wäre diese Symmetrie ohne die, für den Computer typische, Interaktivität? Also habe ich (zunächst mit Processing aber dann mit) HTML5-Canvas eine kleine Javascript-Sache gebastelt, mit der man direkt im Browser symmetrisch zeichnen kann.

Irgendwie macht das Spaß und, naja, es sieht auch oft erstaunlich gut aus.

Zum Zeichenbrett. Tipp: Man kann in der URL die Anzahl der Punkte verändern.

Und hier noch ein Video:


Drawing Symmetry (6)

Viel Spaß beim Malen!

Kommentare: 2 Einträge

Javascript Regular Expressions Beispiele

03.11.2009, 18:18

Viele Javascript-Tutorials zum RegExp-Objekt benutzen die RegExp.$1-Notation und andere unschöne Dinge. Außerdem gibt es mehrere nahezu äquivalente Funktionen, was Reguläre Ausdrücke angeht. Darum habe ich ein Bisschen herumgespielt mit den Funktionen S.match(R), R.exec(S), R.test(S), S.split(R), S.replace(R) und S.search(R). Hier ist die kleine Referenz mit viel Beispiel, mit der ich hoffe arbeiten zu können:

RegExp-Objekte erstellen

// short constructor
var regexp=/a(b?c)/i

// long constructor
var regexp=new RegExp("a(b?c)","i"):
// -> allows runtime configuration
var char="a";
var regexp=new RegExp(char+"(b?c)",'i');

In der Praxis wird man fast immer den kurzen Konstruktor verwenden. Manchmal lässt sich ein dynamisches Erstellen des RegExps vermeiden, indem man den Treffer überprüft.

Finden mit String.match(RegExp) und RegExp.exec(String)

// match: basic usage
"a".match(regexp);   //  null
"abc".match(regexp); // ["abc", "bc"]
// -> "i"-flag: caseinsensitive
"Ac".match(regexp));  // ["Ac", "c"]
"acb".match(regexp); // ["ac", "c"]

// exec: same but method of regexp
regexp.exec("a");   //  null
regexp.exec("abc"); // ["abc", "bc"]
regexp.exec("Ac");  // ["Ac", "c"]
regexp.exec("acb"); // ["ac", "c"]

Bis auf wenige Ausnahmen (siehe unten) sind die beiden Funktionen gleich. Zurückgegeben wird ein Array mit dem gesamten passenden Teil und den im regulären Ausdruck eingeklammerten Teilen.

Prüfen mit RegExp.test(String)

// test: just booleans
/^abc$/.test("abc"); // true
/^abc$/i.test("AbC"); // true
/^abc$/.test("abcd"); // false

Diese Funktion ist zum Validieren von Eingaben recht praktisch, wenn es nicht auf den Inhalt des Strings ankommt.

Teilen mit String.split(RegExp)

// split: arrayify stings
"a,b,c.d".split(/\.|,/) // ["a", "b", "c", "d"]
"a,.b- c .d_e".split(/[.,-_]/) // ["a", "", "b", " c ", "d", "e"]
"a,.b- c .d_e".split(/[.,-_\s]*/) // ["a", "b", "c", "d", "e"]

Das Teilen kann auch mit einem normalen String geschehen, aber mit einem RegExp lassen sich, wie in diesem Beispiel demonstriert erweitere Funktionen implementieren, wie mehrere mögliche Trennzeichen oder das kürzen von Whitespace und leeren Elementen.

Lokalisieren mit String.search(RegExp) und RegExpResult.index

// search: match position
"0123b56b".search(/b/g); // 4
"0123b56b".search(/x/g); // -1

// index: match position, too
/b/.exec("0123b56").index; // 4
"0123b56".match(/b/).index; // 4
// -> "g"-flag:global
/b/g.exec("0123b56b").index; // 4
"0123b56b".match(/b/g).index; // undefined

Interessant ist, dass match und global sich nicht vertragen. Irgenwie ist es schon eine rechte Eigenart dass sich gobale und nicht-globale Ausdrücke so startk unterscheiden, daher würde ich RegExp-Objekte nicht zu weit durch Methodenaufrufe schicken.

Ersetzen mit String.replace(RegExp,replacement)

// replace
var string="ab-ghi-abc-hl-ac"
string.match(regexp); // ["abc", "bc"]
string.replace(regexp,"#")); // "ab-ghi-#-hl-ac"

Globales Finden und Ersetzen

// more global
var regexp2=new RegExp(regexp.source,'g')
string.replace(regexp2,"#"); // "ab-ghi-#-hl-#"
string.match(regexp2); // ["abc", "ac"]
// loop like that:
regexp2.exec(string); // ["abc", "bc"]
regexp2.exec(string); // ["ac", "c"]]
regexp2.exec(string); // null
regexp2.exec(string); // ["abc", "bc"]

Hier unterscheiden sich match() und exec()! Während match() ein Array der allen Treffern aus den kompletten Trefferstellen liefert, liefert exec(), wie beim nicht-globalen, pro Fundstelle je ein Array inclusive Klammerstellen. Um mit exec() alle Treffer zu erhalten, kann man z.B. eine while-Schleife verwenden.

Backreferences

// backreferences
/([ab])c\1/.test("aca"); // true
/([ab])c\1/.test("bcb"); // true
/([ab])c\1/.test("bca"); // false

// replacement backreference
// notice 1-9 limitation
"ll mm kk kx a Bb lL".replace(/([lkb])\1/gi,"$12")
"l2 mm k2 kx a B2 l2"
// beyond 1-9
"abcdefghijklmnopqrst".replace(/(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)/i,"$13-$1-$13+++") // "m-a-m+++qrst"
"abcdefghijklmnopqrst".replace(/(.)(?:.)(?:.)(?:.)(?:.)(?:.)(?:.)(?:.)(?:.)(?:.)(?:.)(?:.)(.)(?:.)(?:.)(?:.)/i,"$2-$1-$13+++") // "m-a-a3+++qrst"
// get a $
"ab".replace(/(.)/,"$$1") // $1b
"ab".replace(/(.)/g,"$$1") // $1$1
// special backrefs:
"abcdefg".replace(/(d)e/,"[ $`-$1-$' (inst $&) ]") // "abc[ abc-d-fg (inst de) ]fg"

Richtig interessante Dinge lassen sich machen mit Backreferences. Grundsätzlich können doppelte Vorkommen von passenden Teilen geprüft werden. Beim Ersetzen sind sie essenziell für Umformatierungen.

Spezialitäten

// special firefox shortcut:
/a/("cba") // a
/a(.)/("acbab") // ["ac", "c"]
// Ein Bonbon:
/\\/("\\")//["\"]
// Noch eines:
function _(é) {var ì=Array,í=RegExp,è=["join","length","replace"],î=[],_
="\x31",_=_*_,ë=_+_+_*_;for (var i=ë;i>=_;i--) {î[î[è[_]]]=("((\\\x64)"+
(new ì(i)[è[_-_]]("\\"+(ë-i+_)*(_+_)))+")");}var î=new í(î[è[_-_]]("|"),
"\x67"),ï=function(){var I=arguments;for(var i=ë;i>=_;i--){var j=(_+_)*(
ë+_-i);if(I[j]) {return i+I[j];}}},ì="",í=_+ì;for (i=_-_;i<é;i++) {ì+=(i
+"\x20"+í+"\n");í=í[è[_+_]](î,ï);}return ì;}alert(_(9));

Der Firefox-Shortcut könnte zwar praktisch sein, wird aber nicht von vielen Browsern unterstützt, und ist auch ein bisschen zu abstrakt.

Letztere Funktion benutzt Backreferences sowohl im RegExp als auch im Ersetzungstext, zudem ersetzt sie Rekursiv und baut das RegExp dynamisch. Außerdem habe ich sie ein bisschen verschlüsselt, da die Berechnung der ausgegebenen Zahlenreihe eigentlich ein Rätsel ist. Wenn man allerdings weiß, dass ich RegExp verwende, fällt die Lösung leichter, und wenn man es gelöst hat, weiß man vielleicht auch warum es ein perfekter Vorwand ist, um sich etwas mit Regulären Ausdrücken zu beschäftigen.

Such-Wiki zu „javascript regexp“

Kommentare: 2 Einträge

Firefox-Tricks für Webentwickler

30.10.2009, 10:12
userContent.css

userContent.css

Der populäre Webbrowser Mozilla Firefox zeichnet sich unter anderem durch viele Add-Ons aus. Jedoch wird nicht jede persönliche Vorliebe durch ein Add-On abgedeckt. Doch wer sich etwas mit Javascript und CSS auskennt, kann auch selbst kleine Einstellungen machen, ohne viel Aufwand. Dazu gibt es mindestens diese vier Möglichkeiten:

Anpassen von userContent.css und userChrome.css

Diese beiden Dateien befinden sich im Unterordner chrome des Firefox-Profilordners und müssen meistens angelegt werden. Sie sind (fast) ganz normale CSS-Stylesheets; Die userChrome.css enthält CSS-Regeln, die auf das XUL-Interface des Browsers, also alle Menüs, Toolbars etc. angewendet werden. So ist es leicht, z.B. die Schriftgröße der Bedienelemente zu vergrößern, oder der Adressleiste eine Monospace-Schriftart zu verpassen. Auf mozilla.org gibt es weitere Beispiele für userChrome.css.

Die Datei userContent.css enthält CSS-Regeln, die auf die angezeigten Webseiten angewendet werden. Ich benutze die Datei, um mich vor gewissen Links zu warnen: Zum Beispiel mag ich es nicht von Google immer auf experts-exchange.com zu klicken. Darum habe ich diese kleine Regel eingebaut, die mittels CSS3-Attribut-Selektor alle Links zu dieser Seite durchstreicht und verblasst:

a[href^="http://www.experts-exchange.com/"] {opacity:0.3 !important; text-decoration: line-through ! important;  }

Das !important bewirkt, dass die Regel die bereits vom Webseitengestalter gesetzten Regeln überschreibt.

Die Regeln lassen sich glücklicherweise auf bestimmte Seiten beschränken, so wie hier:

@-moz-document url(http://twitter.com/), url(http://twitter.com/home)
{
.latest-status {background-color:#FFFFC9;}
}

Diese Regel hinterlegt z.B. die letzte selbst geschriebene Nachricht im Stream von twitter.com mit einem leichten Gelb. Das erleichtert zu sehen, was wann passiert ist.

Eigene Sidebars

Wer Plattform-übergreifende Widgets basteln will, kann auf die Firefox-Sidebar zurückgreifen. In dieser lassen sich beliebige Webseiten anzeigen. Dazu muss man lediglich ein besonderes Lesezeichen erstellen, dass dann immer in der Sidebar geöffnet wird:

Sidebar Lesezeichen

Sidebar Lesezeichen

Man kann also wenn man etwas Bildschirmplatz opfern will, selbst gemachte Widgets anzeigen lassen. Der Link im Screenshot verweist auf eine Seite, die nur ein Textfeld enthält, um schnell Notizen zu machen oder als erweiterte Zwischenablage. Doch die Möglichkeiten sind nahezu unbegrenzt (Monitoring, Feeds, ...?).

Bookmarklets

Bookmarklets führen auf Knopfdruck bestimmte Javascript-Schnippsel auf einer Webseite aus, und funktionieren dabei nicht nur im Firefox. Dazu muss man den JS-Code von Zeilenumbrüchen befreien, alle Leerzeichen mit %20 kodieren und das Ganze dann umschließen mit:

javascript:(function(){/*here goes the code*/})();

So wird das Script zu einem Javascript-Link, der dann als Lesezeichen gespeichert werden kann. Ich habe mir z.B. ein Twitter Bookmarklet gebastelt. Außerdem einen DOM-Performance-Tester:

javascript:(function(){var%20d=0,l=500,n=document.getElementsByTagName('*').length;for(var%20i=0;i<l;i++){document.body.style.display='none';var%20s=Number(new%20Date());document.body.style.display='';var%20h=document.body.clientHeight;d+=Number(new%20Date())-s;}alert('Reflow:%20'+(d/l)+'%20ms%20('+Math.round(1000/(d/l))+'%20fps)\nDOM-Nodes:%20'+n+'\nRewlow%20per%20node:'+Math.round(1000000*d/(l*n))+'%20ns');})()

DOM-Benchmark

Das Kurze Script ermittelt, wie lange der Browser für einen Seitenaufbau braucht und wie viele DOM-Knoten das Dokument enthält. Es ist praktisch, wenn man komplexere Javascript-Animationen oder ähnliches erstellt, die langsam wirken. Dann offenbart der Test, ob nicht zu viele DOM-Knoten oder komplizierte CSS-Regeln die Seite verlangsamen.

Faustregel: Je weiter hinten ein Selektor steht, desto weniger Elemente sollten auf ihn passen, also li #id ist schneller als #id li, wobei sich das besonders in Verbindung mit CSS-Expressions bemerkbar macht.

Greasemonkey

Um auf bestimmten Seiten JS-Code auszuführen, gibt es das Firefox-Plugin Greasemonkey. Zu diesem Add-On gibt es nicht nur ein großes Repositorium existierender sog. Userscripts, sondern man kann auch schnell ein eigenes Script erstellen, um auf bestimmten Webseite irgendetwas anzupassen. Außerdem kann man jQuery benutzen mit folgender Zeile im Header:

// @require http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js

Ich habe z.B. ein Quick Search-Userscript gebastelt, welches beim Auswählen von Text ein kleines Menü öffnet, sodass ich den Text z.B. googlen, übersetzen oder twittern kann.

Es gibt also mehr effektive Möglichkeiten Firefox anzupassen, als das installieren von Add-Ons.

Kommentare: keine

3D-Perspektive mit einer kurzen Formel

04.09.2009, 19:07
3D-Effekt mit Javascript

3D-Effekt mit Javascript

Für die Gestaltung von 3D-Effekten, sind zwar duzende Hardware-beschleunigte Toolkits parat, doch im Fall von HTML-Canvas bzw. auf Webseiten generell sieht das Angebot nicht so reich aus. Das hat mich dazu bewegt, selbst einen kleinen Blick in die Mathematik hinter 3D-Projektionen/3D-Perspektive zu werfen. Meine Erkenntnisse konnte ich in einer kurzen Formel zusammenfassen.

Wer sich nicht für die Mathematik interessiert, kann natürlich flash oder eine der vielen Canvas-3D-Librarys verwenden.

Das Prinzip hinter der 3D-Projektion ist meist das einer Lochkamera. Lichtstrahlen fallen vom abzubildenden Punkt im Raum durch ein Loch und auf einen Schirm. Diese Art der Projektion war eine der ersten bekannten und mit ihrer alten Bezeichnung „camera obscura“ (lat. für dunkle Kammer, die in der der Schirm angebracht war) namensgebend für die heute auf Linsenoptik basierenden Kameras.

Die Lochkamera ist leider nicht so lichtstark wie die Linsenoptik und ihre Schärfe ändert sich nicht mit der Entfernung, sondern mit der Größe des Lochs.

Im Gegensatz zur Linsenoptik ist die Lochkamera aber durch den einfachen Strahlensatz zu berechnen. Mit dem Strahlensatz kann man ganz einfach die Koordinaten eines Punktes im Raum umrechnen in Koordinaten auf dem Schirm. Dazu genügt folgende Funktion:

F:ℝ³→ℝ², F(x,y,z)= P( x*d / z | y*d / z ) ; d: distance to screen

Dass diese Funktion klappt, zeigt dieses Beispiel. Hier eine Graphische Erläuterung:

Strahlensatz für Perspektive. Schwarz: Abzubildender Punkt/Lichtstrahl, Blau: Kamera, Grün: Kameraparameter Bildweite, Rot: Koordinate auf dem Schirm, Lila: Ursprungskoordinaten

Strahlensatz für Perspektive. Schwarz: Abzubildender Punkt/Lichtstrahl, Blau: Kamera, Grün: Kameraparameter Bildweite, Rot: Koordinate auf dem Schirm, Lila: Ursprungskoordinaten

Wegen dem Strahlensatz gilt x' / x = d / z, aufgelöst x' = d*x / z, analog für die y-Koordinate.

Etwas logischer wäre vielleicht der Schirm hinter dem Loch, vor allem da Objekte näher an die Kamera heran kommen können, doch so kann man sich den Schirm wie den Computerbildschirm vorstellen, durch den man in die Raumillusion hineinschaut.

Diese Formel erledigt die Abbildung in der Kamera. Jedoch muss der Punkt bereits in Koordinaten relativ zur Kamera gegeben sein. Da man normalerweise Punkte zunächst durch ein Weltkoordinatensystem definiert, muss man sie erst transformieren.

Bei meinem einfachen Beispiel beschränkt sich die Transformation zunächst auf eine Verschiebung entlang der z-Achse und später habe ich noch eine Rotation um die y-Achse hinzugefügt. Diese Koordinatenumrechnungen lassen sich in Transformationsmatrizen beschreiben.

Dann fehlt eigentlich nur noch die Darstellung. Im Beispiel wird der Text durch einfache CSS-Manipulationen an die richtige Position gebracht, und die Kreise werden mit dem canvas-Element gerendert.

Mit einem solchen Modell lassen sich schon einfache Drahtgitter problemlos darstellen (Demo), da eine Kante zwischen zwei Punkten im Raum auch eine Strecke zwischen zwei Punkten auf dem Schirm darstellt, und uns somit die Berechnung dieser Bildpunkte erspart. Für eine ausgefeiltere Darstellung kann man Dreiecke oder Polygone verwenden (Demo), für die ungefähr das selbe gilt, nur dass z.B. ihr Winkel zu einer Lichtquelle für die Kolorierung verwendet werden kann

Für nahezu realistische Lichteffekte bedarf es allerdings eines anderen Modells, genannt Raytracing, bei dem man den Weg rückwärts geht und bei der Kamera anfängt. Das wurde übrigens auch schon in Javascript umgesetzt, ist aber für Echtzeit-Anwendungen eher ungeeignet (vielleicht kommen bald die ersten Computerspiele mit der - in Realtime - noch neuen Technik).

Kommentare: keine

jQuery Plugin intoViewport

06.08.2009, 20:08

Das Plugin intoViewport erledigt als Erweiterung zu der populären Javascript-Bibliothek jQuery das scrollen bestimmter HTML-Elemente einer Webseite in den Sichtbereich des Browsers, aber nur wenn nötig und nur so weit wie nötig. Es hat nur eine Größe von 480 Byte (minified).

Demo

Dieses minimale jQuery-Beispiel würde den 4. Link auf der Seite in das Darstellungsfeld des Betrachters scollen:

$('a').eq(4).intoViewport();

Scrollen - so viel wie nötig und so wenig wie möglich

Das Script vergleicht jeweils Höhe und Y-Position des übergebenen DOM-Elements und des aktuell sichtbaren Seitenausschnitt des Browsers (Viewport).

Sollte das Element über den Viewport herausragen, oder gar komplett über diesem sein, scrollt es so weit nach oben, bis das gesamte Element sichtbar ist, also wird die Oberkante des Ausschnitts an die Oberkante des Elements verschoben.

Sollte das Element hingen weiter unten liegen, scrollt es nach unten, und wiederum nur so weit, dass es Element gerade sichtbar ist.

Ist das Element schon komplett im Viewport, so tut es überhaupt nichts. Die Scroll-Maßnahmen sind möglichst restriktiv gehalten, da scrollen ungefragt, oder gar sinnlos, den Benutzer der Seite für gewöhnlich verwirrt.

Im Fall, dass das Element größer als das Browserfenster ist, versucht das Plugin möglichst viel des Elements anzuzeigen und scrollt die Oberkante des Elements an den Oberen Bildschirmrand, sodass man immer noch oben beginnen kann zu Lesen.

Wieso, Weshalb, Warum?

Das Plugin soll verhindern, dass, beispielsweise mit jQuery, später eingeblendete Elemente vom Surfer unbemerkt erscheinen, wie Warnmeldungen.

Benötigt habe ich das Plugin auch für meine Suchfunktion, wo nach Möglichkeit die Ergebnisliste komplett angezeigt werden soll. Denn hier sind versteckte Teile fatal: man tippt (meist) mit beiden Händen und kann daher nicht scrollen. Außerdem wird bei der Tastaturnavigation durch die Suchergebnisse der Bildschirmausschnitt dem gewählten Ergebnis folgen.

Die Einsatzgebiete sind sicher noch vielfältiger und der Kreativität sind, wie immer, keine Grenzen gesetzt.

Es grenzt sich von der Javascript-Funktion scrollIntoView() dadurch ab, dass es sanft (animiert) scrollen kann, dadurch den User nicht total orientierungslos lässt. Zwar gab es schon Lösungen zum sanften Scrollen mit jQuery, aber diese beinhalteten leider nicht den Test, ob und wie weit gescrollt werden muss.

Der Javascript-Quelltext

Für Interessierte, hier der Sourcecode des Plugins:

(function($) {
  jQuery.fn.intoViewport = function(options) {
    options = $.extend({
      // Configuration
      // Add whatever options animate schould get by default
      duration:  200,
      easing: "swing"
    }, options || {});
    return this.each(function(){
      // scroll to certain destination:
      function scrTo(dest) {
        $("html,body").stop().animate({ scrollTop: dest}, options );
      }
      var
        //current viewport Y-position
        scr=$(document).scrollTop()||$(window).scrollTop(),
        // viewport Y-size
        wheight=$(window).height(),
        // element Y-position
        top=$(this).offset().top,
        // element Y-size
        eheight=$(this).outerHeight();
        // case element before viewport:
        if (scr>top) {
          scrTo(top); // scroll up to element
        // case viewport before element (bottom part of e. outside):
        } else if (scr!=top && top+eheight>scr+wheight) { 
          // scroll down till everything is inside
          scrTo(top+Math.min(eheight-wheight,0));
          //              ^ but don't hide top part again
        }
      });
    };
})(jQuery); //compatibility

Ich habe das Plugin allerdings nicht nicht in zu vielen Browsern und Situationen getestet. Daher könnte es sein, dass es in einigen Browsern nicht funktioniert. Auch könnte es Probleme geben, wenn die Elemente innerhalb von scrollbaren Elementen liegen, wie <div>s mit der CSS-Eigenschaft overflow:auto;.

Kommentare: 2 Einträge
[ Seite 1 2 ] Nächste Seite »
 
Χρόνογραφ
© 2008-2010 by Bernhard Häussner - Impressum - Login
Kurz-Link zur Homepage: http://1.co.de/