Wednesday, February 27, 2013

mcMapper

mcMapper (Michael Cornetto mapper) is a client side GIS application I created to allow a user to mash-up maps from disparate sources.  It’s still in it’s early stages but it’s a great example of what can be done with Ext JS and OpenLayers.

I went for a very stark interface.  To pan around the map, click the map and drag.  To zoom in and out of the map, use the mouse wheel.   In the illustration below, I’m zoomed in around Mesquite, Texas.

 

You can change the background map by clicking an unselected radio button in the Base category of the Layers sidebar.

As a note, the sidebar is split from the map and may be resized  by adjusting the splitter bar or collapsed by clicking on the arrow mid-way down the splitter bar.

If you want to add additional layers to the drawing, check the checkbox for that layer.  In the example below I am adding Mesquite Texas Parks.   This data is served directly from the Mesquite Texas web site,  http://www.cityofmesquite.com/.

Features from any vector layer added may be selected.  Click the map over a park.  A menu will be presented containing the names of the parks near the mouse cursor.  In the Mesquite Texas Park layer, these names are actually numbers.

Select the park of interest and the supplied attributes for that park will be displayed.  In the example below, I’ve selected park # 49.

The properties dialogue is pinned to the position.  Move the map around and the dialogue moves with it.  Either click the close button on the top right or select another feature to close the properties dialogue. 

When you leave the site and then return, the map you’ve created will be remembered. 

That’s it for now.  In the future additional functionality, such as drawing and adding and removing layers, will be added.

Friday, February 1, 2013

mclib–my personal javascript library

Though there are plenty of libraries that do many things for the average javascript programmer, there’s always things they don’t seem to do.  Or maybe they do the function but not quite the way you want.  Either way, there’s always going to be need for you to write some functions that you use time and again. This is my library of those functions, Michael Cornetto’s library, mclib.  You can find the documentation for it here.

Download mclib.zip

It’s a bit small at the moment because I threw it together specifically to support Process Lists and Pouches but it will be added to in the future.  Currently it contains four namespaces and classes.

  • object: Contains object related functions like merge.
  • Event: A simple generic Event object.
  • pouch: A contained piece of passable storage that can be destroyed once used.
  • ProcessList: A list of processes that will be executed asynchronously but in order . 

mclib.pouch

Pouches are pieces of storage (an object) that is destroyable once used.  This isn’t strictly necessary when using javascript but when writing a large application in javascript every piece of information you don’t need, that you can clear from memory, is helpful. 

I find pouches useful when using ExtJS windows. Here’s one example of how I would use them.  In this example both the window and the pouch are destroyed when the close button is clicked.

        var pouch = mclib.pouch.get();
pouch.pop =
new Ext.Window({
buttons: [{
text:
"Close",
handler:
function (button, event) {
pouch.destroy({ close: pop });
}
}],
listeners: {
close:
function (panel) {
if (!pouch.destroying) {
pouch.destroy();
}
}
}
});

mclib.ProcessList


A Process List is a list of processes that will be executed asynchronously but in order.  This is useful if performing involved calculations on each item in an array of objects.   I find pouches useful when using OpenLayers.  Here’s an example that iterates through all the features on a layer and performs calculations on each feature.

        var list = new mclib.ProcessList();

list.progress.addHandler(
function (argsObj) {
//use argsObj.processed (number processed)
//to update your progress bar.
});

for (var i = 0, l = layer.features.length; i < l; i++) {
list.add(calculate, { feature: layer.features[i] });
}

function calculate(argsObj) {
//use argsObj.feature to access the feature
//then calculate away...
}

Because of IE’s design, Process Lists work better in Chrome than in IE. 


If you do decide to use this library please remember this is a first release.  If you have any problems, let me know.   

Monday, February 2, 2009

RSS Reader using Javascript

After playing around with other packaged Widgets that read and display RSS feeds, I found most really didn’t do exactly what I wanted them to do.  So I checked around looking for one that used Javascript.

I found this site that had a tutorial.  And that was pretty sweet but the code was all in pieces.  So I assembled the code and to my surprise it didn’t work.  I fixed the code and thought you might like to have a copy.

// JavaScript Document
function getRSS()
{
    if (window.ActiveXObject) //IE
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
    else if (window.XMLHttpRequest) //other
        xhr = new XMLHttpRequest();
    else
        alert("your browser does not support AJAX");

    xhr.open("GET",document.rssform.rssurl.value,true);

    xhr.setRequestHeader("Cache-Control", "no-cache");
    xhr.setRequestHeader("Pragma", "no-cache");
    xhr.setRequestHeader("Content-Type", "text/xml");

    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4)
        {
            if (xhr.status == 200)
            {
                if (xhr.responseText != null)
                {
                    xhr.responseXML.loadXML(xhr.responseText);
                    processRSS(xhr.responseXML);
                }
                else
                {
                    alert("Failed to receive RSS file from the server - file not found.");
                    return false;
                }
            }
            else
                alert("Error code " + xhr.status + " received: " + xhr.statusText);
        }
    }

    xhr.send(null);
}

function processRSS(rssxml)
{
    RSS = new RSS2Channel(rssxml);
    showRSS(RSS);
}
function RSS2Channel(rssxml)
{
    /*required string properties*/
    this.title;
    this.link;
    this.description;

    /*optional string properties*/
    this.language;
    this.copyright;
    this.managingEditor;
    this.webMaster;
    this.pubDate;
    this.lastBuildDate;
    this.generator;
    this.docs;
    this.ttl;
    this.rating;

    /*optional object properties*/
    this.category;
    this.image;

    /*array of RSS2Item objects*/
    this.items = new Array();

    var chanElement = rssxml.getElementsByTagName("channel")[0];
    var itemElements = rssxml.getElementsByTagName("item");

    for (var i=0; i<itemElements.length; i++)
    {
        Item = new RSS2Item(itemElements[i]);
        this.items.push(Item);
    }

    var properties = new Array("title", "link", "description", "language", "copyright", "managingEditor", "webMaster", "pubDate", "lastBuildDate", "generator", "docs", "ttl", "rating");
    var tmpElement = null;
    for (var i=0; i<properties.length; i++)
    {
        tmpElement = chanElement.getElementsByTagName(properties[i])[0];
        if (tmpElement!= null)
        {
            if (tmpElement.childNodes[0]!=null)
            {
                eval("this."+properties[i]+"=tmpElement.childNodes[0].nodeValue");
            }
            else
            {
                eval("this."+properties[i]+"=''");
            }
         }
    }

    this.category = new RSS2Category(chanElement.getElementsByTagName("category")[0]);
    this.image = new RSS2Image(chanElement.getElementsByTagName("image")[0]);
}
function RSS2Category(catElement)
{
    if (catElement == null) {
        this.domain = null;
        this.value = null;
    } else {
        this.domain = catElement.getAttribute("domain");
        this.value = catElement.childNodes[0].nodeValue;
    }
}
function RSS2Image(imgElement)
{
    if (imgElement == null) {
    this.url = null;
    this.link = null;
    this.width = null;
    this.height = null;
    this.description = null;
    } else {
        imgAttribs = new Array("url","title","link","width","height","description");
        for (var i=0; i<imgAttribs.length; i++)
            if (imgElement.getAttribute(imgAttribs[i]) != null)
                eval("this."+imgAttribs[i]+"=imgElement.getAttribute("+imgAttribs[i]+")");
    }
}
function RSS2Item(itemxml)
{
    /*required properties (strings)*/
    this.title;
    this.link;
    this.description;

    /*optional properties (strings)*/
    this.author;
    this.comments;
    this.pubDate;

    /*optional properties (objects)*/
    this.category;
    this.enclosure;
    this.guid;
    this.source;

    var properties = new Array("title", "link", "description", "author", "comments", "pubDate");
    var tmpElement = null;
    for (var i=0; i<properties.length; i++)
    {
        tmpElement = itemxml.getElementsByTagName(properties[i])[0];
        if (tmpElement != null)
        {
            if (tmpElement.childNodes[0]!=null)
            {
                eval("this."+properties[i]+"=tmpElement.childNodes[0].nodeValue");
            }
            else
            {
                eval("this."+properties[i]+"=''");
            }
         }
    }

    /*C*/
    this.category = new RSS2Category(itemxml.getElementsByTagName("category")[0]);
    this.enclosure = new RSS2Enclosure(itemxml.getElementsByTagName("enclosure")[0]);
    this.guid = new RSS2Guid(itemxml.getElementsByTagName("guid")[0]);
    this.source = new RSS2Source(itemxml.getElementsByTagName("source")[0]);
}
function RSS2Enclosure(encElement)
{
    if (encElement == null) {
        this.url = null;
        this.length = null;
        this.type = null;
    } else {
        this.url = encElement.getAttribute("url");
        this.length = encElement.getAttribute("length");
        this.type = encElement.getAttribute("type");
    }
}

function RSS2Guid(guidElement)
{
    if (guidElement == null) {
        this.isPermaLink = null;
        this.value = null;
    } else {
        this.isPermaLink = guidElement.getAttribute("isPermaLink");
        this.value = guidElement.childNodes[0].nodeValue;
    }
}

function RSS2Source(souElement)
{
    if (souElement == null) {
        this.url = null;
        this.value = null;
    } else {
        this.url = souElement.getAttribute("url");
        this.value = souElement.childNodes[0].nodeValue;
    }
}

function showRSS(RSS)
{
    /*A*/
    var imageTag = "<img id='chan_image'";
    var startItemTag = "<div id='item'>";
    var startTitle = "<div id='item_title'>";
    var startLink = "<div id='item_link'>";
    var startDescription = "<div id='item_description'>";
    var endTag = "</div>";

    /*B*/
    var properties = new Array("title","link","description","pubDate","copyright");
    for (var i=0; i<properties.length; i++)
    {
        eval("document.getElementById('chan_"+properties[i]+"').innerHTML = ''"); /*B1*/
        curProp = eval("RSS."+properties[i]);
        if (curProp != null)
            eval("document.getElementById('chan_"+properties[i]+"').innerHTML = curProp"); /*B2*/
    }

    /*show the image*/
    document.getElementById("chan_image_link").innerHTML = "";
    if (RSS.image.src != null)
    {
        document.getElementById("chan_image_link").href = RSS.image.link; /*C1*/
        document.getElementById("chan_image_link").innerHTML = imageTag
            +" alt='"+RSS.image.description
            +"' width='"+RSS.image.width
            +"' height='"+RSS.image.height
            +"' src='"+RSS.image.url
            +"' "+"/>"; /*C2*/
    }

    document.getElementById("chan_items").innerHTML = "";
    for (var i=0; i<RSS.items.length; i++)
    {
        item_html = startItemTag;
        item_html += (RSS.items[i].title == null) ? "" : startTitle + RSS.items[i].title + endTag;
        item_html += (RSS.items[i].link == null) ? "" : startLink + RSS.items[i].link + endTag;
        item_html += (RSS.items[i].description == null) ? "" : startDescription + RSS.items[i].description + endTag;
        item_html += endTag;
        document.getElementById("chan_items").innerHTML += item_html; /*D1*/
    }

    return true;
}

This requires a piece of HTML that looks something like this.

<html>
<head>
    <!--B-->
    <script language="javascript" src="rssajax6.js"></script>
    <!--C-->
    <style type="text/css">
        #chan_items { margin: 20px; }
        #chan_items #item { margin-bottom: 10px; }
        #chan_items #item #item_title { font-weight: bold; }
    </style>
</head>
<body>
    <!--A-->
    <form name="rssform" onsubmit="getRSS(); return false;">
        <select name="rssurl">
            <option value="mylinkfeedrss.xml">test RSS feed</option>
            <option value="google-rss.xml">google RSS feed</option>
        </select>
        <input type="submit" value="fetch rss feed" />
    </form>

    <div id="chan">
        <div id="chan_title"></div>
        <div id="chan_link"></div>
        <div id="chan_description"></div>
        <a id="chan_image_link" href=""></a>
        <div id="chan_items"></div>
        <div id="chan_pubDate"></div>
        <div id="chan_copyright"></div>
    </div>
</body>
</html>

I played around a bit with the HTML and the output of mine and it looks something like this.

You won't get the full effect of this because of the width, but you should get a general idea of how it works.  This is my feed from eclectic-screenplays.blogspot.com.

One thing to note, you cannot get a cross domain XML file.  Therefore you either have to generate the RSS on that domain, get a server proxy that will move the RSS to your server, or just ftp the RSS file to your server.  I’m doing the latter at the moment.

Enjoy!

Wednesday, January 28, 2009

Photos on Freewebs

As if there weren’t enough places on the web to keep your photos, you can also keep some on Freewebs? The interface is fairly easy to use. First thing you need to do is log in. Once you are logged in go to the Site Manager. Or you can even go there from the Site Builder. If we were to continue from the Calendar tutorial it would looks something like this.

image

Select Photos from the drop down located at the top left hand corner of the screen.

image

You can either select an Album to edit or select Add album, which is exactly what we are going to do.

image

Enter a New Album in the space provided or if you decide you really wanted to put it in an Existing Album then select that option and choose the album from the list.

Then Upload your photos. You can do this from you local computer by selecting Upload Photos.

image

You’ll get a familiar file dialog. Choose the file you want to upload from your local computer and select Open.

You can also put photos you have already uploaded into your album by selecting My Images. This tab will list all the images you have already uploaded to Freewebs.

image

Choose the images you want to add. Choosen images will be highlighted. Once you have the correct images for the album click Submit.

image

Congratulations, you have an album with some photos in it on Freewebs.

image

You can edit the album from this screen. Choosing which Photo to use for the album cover. Adding titles and description for the Photos and the album. You can even do some minor photo manipulations, like rotate, from this screen. Don’t forget to select Save when you are done.

Select this link to see this album on Freewebs.

Calendars on Freewebs

Were you wondering how to use the calendars on Freewebs? It’s very easy. First thing you need to do is log in. Once you are logged in go to the Site Manager. Or you can even go there from the Site Builder. If we were to continue from the Blogging tutorial it would look something like this.

image

Select Calendar from the drop down located at the top left hand corner of the screen.

image

And you will be presented with the Calendar screen. Select Add Event to add an event to the calendar.

image

Enter a Title for the event an any rich text Description you desire for the details. Set a Start Time and an End Time. You can also select All Day Event if the event is going to be a long one. Once you have the Add a Calendar event form filled out, then select Submit.

image

And your event will be recorded for posterity.

Next up: Photos

Blogging on Freewebs

Or I should call it webs now.

www.freewebs.com was a site I used to use for file storage. I never actually cared that you could actually create a website there and didn’t use that functionality. This year I started using it and they have also been improving it. Now you can get a pretty full featured website up pretty quickly.

I figured I’d put up some tutorials at using some of the features. One because I’m always looking for something to blog about lately and two because I think these tutorials will help someone out.

The first tutorial is blogging and the first step is to log into freewebs by typing your username and password in the boxes provided.

image

You will be presented with the dashboard for your account.

image

Move your mouse over Edit My Site and a drop down menu will appear. Select Site Manager from the drop down menu.

image

Since we are blogging select Blog from the list of pages.

image

And you will be presented with the Site Builder for you Blog. Select Post New Entry.

image

Enter a Title and use the rich text box to enter the body for your blog entry. You have a lot of formatting control over the rich text box and you can add images or embed video.

image

Select the Publish button when you are finished.

image

And you’ll have your first blog entry on Freewebs. Here is a link to the actual blog entry. Next up: Calendars

WARNING: Webs.com has been freezing sites for very little reason and often don’t respond to inquires about the freeze.  Just letting you know.

Monday, January 26, 2009

Blidgets

Not only can you find interesting widgets at WidgetBox, but you can also create your own.

Click this link to Make a Widget. You will be presented with the following screen.

image

Choose Blog/Feed and you will be prompted for your blog feed url.

image

Enter your feed url and continue and it attempts to generate your blidget but I don’t think it will be exactly what you want, you’ll need to customize it.

image

Customize the blidget. By choosing the Appearance – I went for the leopard skin.

image

And the content – I went for the slide show.

image

And finally the cataloguing details. People can search for your finished widget – if you want them to.

image

Once you save the widget, you will get the widget screen. This is the screen that anyone who wants your widget will see. You can further customize your widget here and then “Get Widget”

image

And you will be given a little box that has the javascript you need to publish your widget on any page.

image

My javascript looks like this.

<script type="text/javascript" src="http://cdn.widgetserver.com/syndication/subscriber/InsertWidget.js"></script>

<script>if (WIDGETBOX) WIDGETBOX.renderWidget('6468a97f-3334-484d-923f-7bbc75305463');</script>

<noscript></noscript>

Once you have the Javascript, just place it wherever you can place html. I use one in my forum signatures.