Radar HUD Demo

What:
* Single prim, single script HUD that shows dots for nearby avatars on a map image.
* Less useful than the mini map.
* Uses LSL's HTTP-In, html 5 canvas and ajax.
* Currently under 16k memory as mono.
To use:
* Create a box, attach it to a HUD point, scale and position as you like.
* Drop this script in it.
* Requires media on a prim be enabled.
Bugs:
* Sometimes it just sits there blank. Not sure how/why. Requires a script restart usually to fix.
TODO:
* Add hover text for people (names)
* Add click action for people (profiles?)
* Rotate the map
* Zoom the map
* Options: scan different things, use different colors.
* Make the dots look better
* Add direction indicator to 'me' dot.
<lsl>
// License: 
// This script itself is free to share, modify and use without restriction.
// Any linked or referenced files are not included in this license and are licensed by their respective owners under their own respective copyright and other licenses. 
// Created by Kelly Linden, 2011.
 
integer display_face = 4;
 
string index_html;
 
build_index(string url)
{
 vector rc = llGetRegionCorner();
 string bg_url = "http://map.secondlife.com/map-1-" + (string)((integer)(rc.x / 256)) + "-" + (string)((integer)(rc.y / 256)) + "-objects.jpg";
 
 // Build the index page.
 index_html = 
"<html><head>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js' />
<script type='text/javascript' language='javascript'>
var me;var req_me = false;
var people;var req_people = false;
 
function plot(ctx, points, color, border, size) {
 if (points != undefined) {
 ctx.fillStyle=color;
 for ( p in points ) {
 ctx.fillStyle=border;
 ctx.fillRect(points[p][0] - 2,points[p][1] - 2,size,size);
 ctx.fillStyle=color;
 ctx.fillRect(points[p][0] - 1,points[p][1] - 1,size - 2,size -2); 
 }
 }
}
 
function updateMap() {
 canvas = document.getElementById( 'myCanvas' );
 ctx = canvas.getContext( '2d' );
 img = new Image();
 img.src = '" + bg_url + "';
 
 if (!req_me) {
 req_me = true;
 $.getJSON('mypos',function(data){me = data;req_me=false;});
 }
 
 if (!req_people) {
 req_people = true;
 $.getJSON('avatars',function(data){people = data;req_people=false;});
 }
 
 ctx.save();
 if (img.complete) {
 ctx.drawImage( img, 0, 0, canvas.getAttribute('width'), canvas.getAttribute('height') );
 }
 
 plot(ctx,people,'#FF0000','#FFFFFF',5);
 plot(ctx,me,'#FFFFFF','#000000',7);
 ctx.restore();
 setTimeout( updateMap, 500 ); 
}
</script><base href='" + url + "/' /></head>
<body style='background: #FFFFFF; width: 100%; height: 100%; margin: 0px;' onLoad='updateMap();'>
<canvas id='myCanvas' width='256' height='256' style='position:fixed; top:0px; left:0px;'>
Canvas unsupported.
</canvas></body></html>"; 
}
 
set_url(string url)
{
 build_index(url);
 
 llSetLinkMedia(LINK_THIS, display_face, // Side to display the media on.
 [PRIM_MEDIA_AUTO_PLAY,TRUE, // Show this page immediately
 PRIM_MEDIA_CURRENT_URL,url, // The url if they hit 'home'
 PRIM_MEDIA_HOME_URL,url, // The url currently showing
 PRIM_MEDIA_HEIGHT_PIXELS,256, // Height/width of media texture will be
 PRIM_MEDIA_WIDTH_PIXELS,256, // rounded up to nearest power of 2.
 PRIM_MEDIA_PERMS_CONTROL, PRIM_MEDIA_PERM_NONE]);
 
 llOwnerSay("Mem: " + (string)llGetUsedMemory());
}
 
default
{
 state_entry() { llRequestURL(); }
 on_rez(integer i) { llResetScript(); }
 changed(integer c)
 {
 if (c & (CHANGED_REGION | CHANGED_TELEPORT | CHANGED_OWNER))
 { llResetScript(); }
 }
 
 http_request(key id, string method, string body)
 {
 if (method == URL_REQUEST_GRANTED)
 {
 set_url(body);
 }
 else if (method == URL_REQUEST_DENIED)
 {
 llOwnerSay("Failed to get url: " + body);
 }
 
 if (method == "GET")
 {
 list path = llParseString2List(llGetHTTPHeader(id,"x-path-info"),["/"],[]);
 
 if (llGetListLength(path) == 0)
 {
 llSetContentType(id,CONTENT_TYPE_HTML);
 
 llHTTPResponse(id,200,index_html);
 }
 else if (llList2String(path,0) == "mypos")
 {
 vector my_pos = llGetPos();
 llHTTPResponse(id,200,"" + (string)((integer)my_pos.x) + "," + (string)(256 - (integer)my_pos.y) + "");
 }
 else if (llList2String(path,0) == "avatars")
 {
 list avatars = llGetAgentList(AGENT_LIST_REGION,[]);
 
 string body = "[";
 integer i;
 integer n = llGetListLength(avatars);
 for(i=0;i<n;++i)
 {
 if (i != 0) body += ",";
 vector pos = llList2Vector(llGetObjectDetails(llList2Key(avatars,i),[OBJECT_POS]),0);
 body += "[" + (string)((integer)pos.x) + "," + (string)(256 - (integer)pos.y) + "]";
 }
 body += " ]";
 llHTTPResponse(id,200,body);
 }
 }
 }
}
</lsl>