Showing posts with label Javascript. Show all posts
Showing posts with label Javascript. Show all posts

Saturday, January 9, 2010

Snowflake SVG developer release

Recently, I have been learning SVG scripting by porting my old branching-web AS3 script to Javascript. This time around, I wanted to remedy some of the shortcomings of the previous incarnation. Here's a list of some of my goals and how they turned out.

Goals

  • Allow the user to customize each node individually, but don't add too much complexity.

    Success. The interface has become slightly more complex, but it's still relatively simple.

  • Let a node have only one child, allowing the user to taper the branches.

    Success. This effect is highly useful for creating snowflake patterns.

  • Improve the demo interface, enabling interactive editing of each node.

    Pending. I plan to tackle this feature next.

Demos

Classic snowflake

Screenshot of a classic snowflake drawn by my library
Click to view as SVG.


function startup(evt) {
    var svgDocument = evt.target.ownerDocument;
    
    var rect = svgDocument.createElementNS(svgNamespace, 'rect');
    rect.setAttributeNS(null, 'fill', 'skyblue');
    rect.setAttributeNS(null, 'width', '100%');
    rect.setAttributeNS(null, 'height', '100%');
    svgDocument.documentElement.appendChild(rect);
    
    var endPoint = createDataNode(0, 0, 0, []);
    var endCap = createDataNode(0, 5, 10, [endPoint]);
    var middleNode = createDataNode(60, 50, 10, [endCap, endCap, endCap]);
    var centerNode = createDataNode(360, 30, 10, [middleNode, middleNode, middleNode, middleNode, middleNode, middleNode]);
    
    var web = createWeb(centerNode, createPoint(0, 0), 0);
    
    var snowflake = createSnowflake(web);
    
    var snowflakeSVG = snowflake.toSVG(svgDocument);
    snowflakeSVG.setAttributeNS(null, 'fill', '#fff');
    snowflakeSVG.setAttributeNS(null, 'transform', 'translate(250 250)');
    svgDocument.documentElement.appendChild(snowflakeSVG);
}

Gothic cross snowflake

Screenshot of a gothic snowflake drawn by my library
Click to view as SVG.


function startup(evt) {

    var svgDocument = evt.target.ownerDocument;
    
    outerPoint = createDataNode(0, 0, 0, []);
    
    taperFork = createDataNode(0, 5, 10, [outerPoint]);
    
    bigFork = createDataNode(180, 25, 10, [taperFork, taperFork, taperFork]);
    
    nextFork = createDataNode(180, 25, 10, [taperFork, bigFork, taperFork]);
    
    innerFork = createDataNode(360, 15, 10, [nextFork, nextFork, nextFork, nextFork]);
    
    var web = createWeb(innerFork, createPoint(0, 0), 0);
    
    var snowflake = createSnowflake(web, innerFork);
    
    var snowflakeSVG = snowflake.toSVG(svgDocument);
    snowflakeSVG.setAttributeNS(null, 'transform', 'translate(250 250)');
    svgDocument.documentElement.appendChild(snowflakeSVG);
}

Nodes displayed as points

Screenshot of a web of nodes drawn by my library
Click to view as SVG


function startup(evt) {

    var svgDocument = evt.target.ownerDocument;
    
    var endPoint = createDataNode(0, 0, 0, []);
    var middleNode = createDataNode(180, 50, 0, [endPoint, endPoint, endPoint, endPoint]);
    var originNode = createDataNode(360, 50, 0, [middleNode, middleNode, middleNode, middleNode]);
    
    var web = createWeb(originNode, createPoint(0, 0), 0);
    var webSVG = web.toSVG(svgDocument);
    webSVG.setAttributeNS(null, 'transform', 'translate(250 250)');
    svgDocument.documentElement.appendChild(webSVG);
}

Download

I've packaged up all the necessary scripts and SVGs into one tiny .zip archive for your hacking pleasure. If you'd like to see what I'm working on next (and possibly help), you can view my Google Code project repository. Everything is licensed under the Apache 2.0 license, so you can use it in a proprietary application, modify it in any way you choose, or pass it to all your friends provided you indicate where it initially came from. If you do anything interesting with it, tell me about it. Happy hacking!

Monday, March 23, 2009

DirSlideShow and MultiSlideShow

These two scripts conceal all server-side directory indexing through a JSON interface, allowing you to set the location of the target pictures through the instantiation of one of the slide shows. If you'd like to see how to use DirSlideShow and MultiSlideShow, please check out this no-jargon tutorial.

DirSlideShow

DirSlideShow takes four arguments, which are listed below.

  • newPictureDir:String — The URL of the directory containing the pictures to be displayed.
  • newslideShowID:String — The id of the HTML element to which the slide show (and possibly control buttons) will be appended.
  • newRotateDelay:Number — The time (in milliseconds) until the next picture is displayed automatically. If the user clicks on one of the control buttons, the slide show will stop progressing automatically.
  • newControlButtons:Boolean — A boolean that determines if two buttons are displayed to allow the user can control the progression of the slide show.

Below is DirSlideShow's function signature:


DirSlideShow = function(newPictureDir, newSlideShowID, newRotateDelay, newControlButtons) {

MultiSlideShow

MultiSlideShow takes two arguments:

  • newPictureDir:String — The URL of a directory which contains the picture directories.
  • newContainerID:String — The id of the HTML element to which the thumbnails will be appended.

Below is the function signature of MultiSlideShow:

MultiSlideShow = function(newPictureDir, newContainerID) {

Download

I am releasing the source code of DirSlideShow and MultiSlideShow under the Apache 2.0 license.

DirSlideShow and MultiSlideShow Source Code

Demonstrations

DirSlideShow Demo

MultiSlideShow Demo

Saturday, March 21, 2009

Two Convenient Javascript Slideshows

I've decided to share two of my most useful Javascript "classes": DirSlideShow and MultiSlideShow. These classes encapsulate the necessary server-side directory indexing so that you can use the slide shows through a pure javascript interface. In other words, they're easy to use. If you'd like to see demonstrations of DirSlideShow and MultiSlideShow or download them now to follow along, please visit their project page.

How about a demonstration?

Let's say that you have a bunch of pictures in the folder images/travelpics of your web server, and you'd like to show them off to your visitors. For this task, you should use DirSlideShow. First, you need to link the scripts to the page, like so:

<script type="text/javascript" language="Javascript" src="scripts/Loader.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/DirSlideShow.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/ArraySlideShow.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/addevent.js"> 
</script>

Once you have access to the classes on your page, you need to create a the slide show by passing in the name of the directory that contains the pictures, the HTML element that will contain your slide show, the time between each change of picture, and whether you want the slide show to have controls. It sounds complex, but it's actually very simple:

<script type="text/javascript" language="Javascript"> 
addEvent(window, "load", init, false);
function init() {
var slideShow = new DirSlideShow("images/travelpics", "travelpicsdiv", 5000, true);
}
</script>

As long as you have an element with an id of travelpicsdiv, the script will find it and put a slide show in it containing the pictures of the directory images/travelpics. It's that simple.

What about the other one?

The other script, MultiSlideShow, is more specialized but probably more useful. For this demo, let's assume that you have taken three trips and put the photos in three separate directories: dubai, honolulu, and newyork. Then, you put all three directories into the directory images. Before you could create a MultiSlideShow, you would have to link to the scripts:

<script type="text/javascript" language="Javascript" src="scripts/Loader.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/MultiSlideShow.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/ArraySlideShow.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/addevent.js"> 
</script>

You would now start a MultiSlideShow by passing only two arguments: the name of the enclosing directory, images, and the id of the div to be filled, travelpicsdiv.

<script type="text/javascript" language="Javascript"> 
addEvent(window, "load", init, false);
function init() {
var slideShow = new MultiSlideShow("images/multislideshow", "multislideshowdiv");
}
</script>

Voila! Your div, travelpicsdiv, will now be dynamically populated with the pictures in dubai, honolulu, and newyork. Once again, there's nothing left to do. Almost.

Configuration

The one assumption that these scripts make is the location of the directory-indexing script relative to the page on which the slide show resides. If your page is in the directory www and your scripts are in the directory www/scripts, the setup will work fine right out of the .zip file. However, if you put your html in a directory www/html and your scripts in a directory www/js, you'll need to do a little configuration. Don't worry; it won't hurt a bit.

There are only two variables in one file that need to be configured: dirIndexURL and htmlPageURL, which are both in scripts/Loader.js. dirIndexURL contains the URL of the script dirindex.php relative to the HTML page that contains the slideshow. htmlPageURL contains the URL of the HTML page relative to the script dirindex.php.

Let's go back to our previous example, in which the page resides in www/html and the script resides in www/js. To re-configure the script, you would replace these lines:

// URL of directory-indexing script relative to HTML page
var dirIndexURL = 'scripts/dirindex.php';
 
// URL of HTML page relative to directory-indexing script
var htmlPageURL = '../';
…with these:
// URL of directory-indexing script relative to HTML page
var dirIndexURL = '../js/dirindex.php';
 
// URL of HTML page relative to directory-indexing script
var htmlPageURL = '../html/';
Now, just reset the script tags properly:
<script type="text/javascript" language="Javascript" src="scripts/Loader.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/DirSlideShow.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/ArraySlideShow.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/addevent.js"> 
</script>

…and set the position of the images relative to the HTML page:

<script type="text/javascript" language="Javascript"> 
addEvent(window, "load", init, false);
function init() {
var slideShow = new DirSlideShow("../images/travelpics", "travelpicsdiv", 5000, true);
}
</script>

And you're done!

I know that there are much flashier slide show scripts available for both Javascript and ActionScript with fancy transitions and flashy picture ribbons. Nevertheless, I'm almost certain that few of those scripts are as convenient, robust, and secure as this one. You can find a full description of these classes' features and usage instructions in their project page.

Monday, January 12, 2009

Are bookmarklets still cool?

I'm by no means an accomplished Javascript programmer, but I'm pretty good at writing small scripts and very lazy when I'm faced with repetitive tasks. So, when I wanted to rip a series of pictures off a website's page (and I had asked permission from the website's owner), I wrote a small Javascript bookmarklet to do it for me.

Just type cut and paste the following code into a bookmark, then click on the bookmark on whichever page has the pictures you want. It will leave you with a page full of image tags you can cut and past onto your own site, provided you got permission from the pictures' owner.

javascript:var htmlDiv = document.createElement('div');var garbageDiv = document.createElement('div');var pageImages = document.images;while (pageImages[0]) {var cleanImage = document.createElement('img');cleanImage.setAttribute('src', pageImages[0].src);htmlDiv.appendChild(cleanImage);garbageDiv.appendChild(pageImages[0]);} var body = document.getElementsByTagName('body')[0];body.style.backgroundColor = '#ffffff';body.innerHTML = '';void(body.appendChild(document.createTextNode(htmlDiv.innerHTML)));

It's a relatively ugly script, but it's easily understandable, nonetheless. It starts by initializing a couple variables: htmlDiv to store the pictures and garbageDiv to hold the pictures that have already been scanned. pageImages just saves me the trouble of typing in document.images over and over again. A simple while loop runs while there is something in the first slot of pageImages. Within the while loop, a new, blank img element called cleanImage is created, given the src of the current picture, and appended to htmlDiv. The current image is then appended to garbageDiv, thus removing it from the page and the pageImages array. Once the loop terminates, the whole page is restyled to have a white background (the website I made it for had a black background) and its contents are replaced by the HTML inside htmlDiv.

If you're wondering, that void() block at the end is necessary because bookmarklets are required to return something. If you didn't have that block there, the last line of code would return true and the only thing left on the screen would be true.

I have at least one more bookmarklet to show off when I again run out of things to say. It's a little more specialized, but it's useful, nonetheless.