JavaScript

A 2-post collection

Raspberry Pi Ajax JavaScript display

3 Raspberry Pis

I recently created a couple eBay store slideshows for a local business. I used two Raspberry Pi's and some CoffeeScript code to fetch images asynchronously. I may release the code later, for now here's an annotated shell script for configuring the Raspberry Pi's.

I sourced these steps from various online guides and did my best to understand each of the command parameters and eliminate those that were superfluous. I also attempted to be consistent in my auto-startup methods, to the best of my ability.

One unique attribute of this configuration is the ability to VNC into either the publicly visible desktop, or a private desktop.

Nginx is installed as a basic webserver because opening our html file locally (file://) doesn't support cross-domain headers for our AJAX requests.

Node.js is installed simply for its package manager, which is used to install the standalone corsproxy tool. This is a simple local proxy for bypassing the same-origin policy restriction that would prevent our cross-domain AJAX requests from succeeding. (I preface my AJAX request URLs with http://localhost:9292/ to use the proxy.)

Other components include hiding the mouse cursor on inactivity and keeping the Raspberry Pi awake.

Chromium is the browser of choice here. I experimented with numerous others but the benefit of similarity to my development environment (Google Chrome) was too great.

This script also configures nginx and sets the site to launch on startup. It assumes the web folder to be at /home/pi/Desktop/web-js and opens main.html, you may need to change these.

When connecting to the Pi with VNC, the public display will be port 5900, the private 5901.

#!/bin/sh

apt-get update

# install x11vnc server for public desktop access (display 0)
apt-get -y install x11vnc

# configure to auto-start
mkdir /home/pi/.config/autostart
cat <<EOM >/home/pi/.config/autostart/x11vnc.desktop
[Desktop Entry]
Encoding=UTF-8
Type=Application
Name=X11VNC
Exec=x11vnc -forever -usepw -bg -ultrafilexfer -display :0
StartupNotify=false
Terminal=false
Hidden=false
EOM

# install tightvncserver for a separate private desktop (display 1)
apt-get -y install tightvncserver

# configure to auto-start
mkdir /home/pi/.config/autostart
cat <<EOM >/home/pi/.config/autostart/tightvnc.desktop
[Desktop Entry]
Encoding=UTF-8
Type=Application
Name=TightVNC
Exec=vncserver :1 -geometry 1600x900 -depth 16 -pixelformat rgb565:
StartupNotify=false
Terminal=false
Hidden=false
EOM

# install basic webserver nginx to handle cross-domain headers (file:// won't work)
apt-get -y install nginx

# configure
cat <<EOM >/etc/nginx/sites-available/web-js
server {
    root /home/pi/Desktop/web-js;
    index main.html
    server_name localhost;
}
EOM

# enable site, disable default
cd /etc/nginx
rm sites-enabled/default
ln -s /etc/nginx/sites-available/web-js sites-enabled/web-js

# install node.js for node package manager
cd ~
wget http://node-arm.herokuapp.com/node_latest_armhf.deb
dpkg -i node_latest_armhf.deb

# install standalone corsproxy tool
npm install -g corsproxy

# hide cursor on inactivity
apt-get -y install unclutter

# install chromium browser
apt-get -y install chromium

# remove chrome didn't shut down safely restore tabs yellow bar
# (this doesn't appear to work)
sed -i 's/"exited_cleanly": false/"exited_cleanly": true/' /home/pi/.config/chromium/Default/Preferences

# keep raspberry pi awake & launch app on startup
cat <<EOM >/etc/xdg/lxsession/LXDE/autostart
# commented these out
#@lxpanel --profile LXDE
#@pcmanfm --desktop --profile LXDE
#@xscreensaver -no-splash

@xset s off
@xset -dpms
@xset s noblank
@corsproxy
@chromium --disable-hang-monitor --kiosk --disable-java --disable-restore-session-state --disable-sync --disable-translate http://localhost
EOM

reboot

Discussion

Facebook group geovisualization

I administer a Facebook group and wanted to visualize the spread of the members on a globe so I looked into using Facebook's Graph API to gather the data. To my surprise I discovered that this is not in the API, there is no available permission for the location of a group member.

Of course since I can view it manually, it's accessible. So I took an alternative route and used jQuery and Ajax, executed from Chrome's JavaScript console on any Facebook page (to avoid a cross-site scripting denial). You first need your own basic access token, which is easy to retrieve by simply visiting Facebook's Graph API Explorer. You also need your group id, retrieved by looking at the link to your group on Facebook. With access token and group id we can assemble the code.

var accessToken = "ACCESS TOKEN GOES HERE";
var groupId = "GROUP ID GOES HERE";
var membersUrl = "https://graph.facebook.com/" + groupId + "/members?fields=id&access_token=" + accessToken + "&callback=?";

$.getJSON(membersUrl, function(members) {
    $.each(members.data, function(i,user) {
        $.ajax("http://www.facebook.com/" + user.id).done(function(data) {
            var match = data.match(/Lives in .+?<\/a>/);
            var location = match && match.length > 0 ? match[0] : "";
            console.log(user.id + ' ' + $(location).text());
        });
    });
});

You may need to use a jQuerify bookmarklet to first load jQuery before executing the code from the console. It uses the Graph API to retrieve member ids, then loads each of their profiles asynchronously, matching the text "Lives in", which is used by the newer Timeline profiles. I couldn't find an older profile or I'd have added support for them. The user id and location is output to the console, where you can simply copy and paste it.

There are a couple of great tools for parsing unstructured geographical data, such as Yahoo Placemaker (here's a nice Python wrapper) and Geodict (works offline).

Finally to actually display the data, WebGL Globe over at Chrome Experiments looks promising, also Geochart. Geochart can be easily limited to a single country as well, for instance using: region: 'US', resolution: 'provinces' with a simple state and member count array yields nice results:

Discussion