window._api = 'Google'; window._start_lat = 35.871334; window._start_lon = -106.326067; /** * \file dragdrop.js * \brief Drag and Drop for maps * * $Revision: 1.3 $ * * Original Author: Sean M. Brennan * $Author: sean_m_brennan $ * * Created: December 12, 2007 * $Date: 2008/02/05 19:30:29 $ */ /* * Copyright 2007. Los Alamos National Security, LLC. This material * was produced under U.S. Government contract DE-AC52-06NA25396 for * Los Alamos National Laboratory (LANL), which is operated by Los * Alamos National Security, LLC, for the Department of Energy. The * U.S. Government has rights to use, reproduce, and distribute this * software. NEITHER THE GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY, * LLC, MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL * LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to * produce derivative works, such modified software should be clearly * marked, so as not to confuse it with the version available from LANL. * * Additionally, this program is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; version 2 of * the License. Accordingly, this program is distributed in the hope * it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. */ /* Portions copyright 2007 by Mark Kahn. * His copyright statement: * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ // requires generic_api.js // requires toolbox.js var myMouseOffset = null; var myMouseDown = false; var myMouseState = false; var myDragObject = null; var myDragDrops = []; var myCurrentTarget = null; var myLastTarget = null; var myDragHelper = null; var myRootParent = null; var myRootSibling = null; var myTargetDiv = ''; var mapDragIdx = 0; Number.prototype.NaN0 = function() { return isNaN(this) ? 0 : this; } function addToolboxEvent(evtObj, evtType, evtFunc) { var oldEvt = evtObj[evtType]; evtObj[evtType] = function(ev) { if (oldEvt) { oldEvt.call(evtObj, ev); } return evtFunc.call(evtObj, ev); } } function writeMessage(message){ var historyDiv = document.getElementById("messages"); historyDiv.appendChild(document.createTextNode(message)); historyDiv.appendChild(document.createElement('BR')); historyDiv.scrollTop += 50; } function CreateDragContainer(div) { var cDrag = myDragDrops.length; myDragDrops[cDrag] = []; for (var i = 0; i < arguments.length; i++) { var cObj = arguments[i]; if (cObj.id == myTargetDiv) { mapDragIdx = cDrag; } myDragDrops[cDrag].push(cObj); cObj.setAttribute('DropObj', cDrag); for (var j = 0; j < cObj.childNodes.length; j++) { if (cObj.childNodes[j].nodeName == '#text') { continue; } cObj.childNodes[j].setAttribute('DragObj', cDrag); cObj.childNodes[j].style.cursor = 'pointer'; } } } function getPosition(e) { var left = 0; var top = 0; while (e.offsetParent) { left += e.offsetLeft + (e.currentStyle ? (parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0); top += e.offsetTop + (e.currentStyle ? (parseInt(e.currentStyle.borderTopWidth)).NaN0() : 0); e = e.offsetParent; } left += e.offsetLeft + (e.currentStyle ? (parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0); top += e.offsetTop + (e.currentStyle ? (parseInt(e.currentStyle.borderTopWidth)).NaN0() : 0); return {x:left, y:top}; } function mouseCoords(ev) { if (ev.pageX || ev.pageY) { return { x:ev.pageX, y:ev.pageY }; } return { x:ev.clientX + document.body.scrollLeft - document.body.clientLeft, y:ev.clientY + document.body.scrollTop - document.body.clientTop }; } function getMouseOffset(target, ev) { ev = ev || window.event; var docPos = getPosition(target); var mousePos = mouseCoords(ev); return { x:mousePos.x - docPos.x, y:mousePos.y - docPos.y }; } function mouseMove(ev){ ev = ev || window.event; var target = ev.target || ev.srcElement; var mousePos = mouseCoords(ev); var dragObj = target.getAttribute('DragObj'); if (dragObj != null && target != null) { // draggable element if (myMouseDown && !myMouseState) { myCurrentTarget = target.cloneNode(true); // copy master object myRootParent = myCurrentTarget.parentNode; myRootSibling = myCurrentTarget.nextSibling; myMouseOffset = getMouseOffset(target, ev); for (var i = 0; i < myDragHelper.childNodes.length; i++) myDragHelper.removeChild(myDragHelper.childNodes[i]); myDragHelper.appendChild(myCurrentTarget.cloneNode(true)); myDragHelper.style.width = parseInt(myCurrentTarget.offsetWidth)+'px'; myDragHelper.style.display = 'block'; // disable dragging from our helper myDragHelper.firstChild.removeAttribute('DragObj'); // Record the current position of all drag/drop targets var dragConts = myDragDrops[dragObj]; myCurrentTarget.setAttribute('startWidth', parseInt(myCurrentTarget.offsetWidth)); myCurrentTarget.setAttribute('startHeight', parseInt(myCurrentTarget.offsetHeight)); myCurrentTarget.style.display = 'none'; // each possible drop container for (var i = 0; i < dragConts.length; i++) { var curDiv = dragConts[i]; var pos = getPosition(curDiv); curDiv.setAttribute('startWidth', parseInt(curDiv.offsetWidth)); curDiv.setAttribute('startHeight', parseInt(curDiv.offsetHeight)); curDiv.setAttribute('startLeft', pos.x); curDiv.setAttribute('startTop', pos.y); // each child element of each container for (var j = 0; j < dragConts[i].childNodes.length; j++) { var curNode = dragConts[i].childNodes[j]; if ((curNode.nodeName == '#text') || (curNode == myCurrentTarget)) { continue; } var pos = getPosition(curNode); curNode.setAttribute('startWidth', parseInt(curNode.offsetWidth)); curNode.setAttribute('startHeight', parseInt(curNode.offsetHeight)); curNode.setAttribute('startLeft', pos.x); curNode.setAttribute('startTop', pos.y); } } } } if (myCurrentTarget) { // dragging myDragHelper.style.top = (mousePos.y - myMouseOffset.y) + 'px'; myDragHelper.style.left = (mousePos.x - myMouseOffset.x) + 'px'; } myMouseState = myMouseDown; myLastTarget = target; myMouseState = myMouseDown; // this prevents items on the page from being highlighted while dragging if (myCurrentTarget || myDragObject) { return false; } } /* mouseMove */ function mouseUp(ev) { ev = ev || window.event; var mousePos = mouseCoords(ev); if (myCurrentTarget) { myDragHelper.style.display = 'none'; myCurrentTarget.style.display = ''; myCurrentTarget.style.visibility = 'visible'; var dragConts = myDragDrops[myCurrentTarget.getAttribute('DragObj')]; var activeCont = null; /** these positions are icon and Map API specific **/ var posX = getIconXOffset(mousePos, myMouseOffset); var posY = getIconYOffset(mousePos, myMouseOffset); for (var i = 0; i < dragConts.length; i++) { var curDiv = dragConts[i]; if ((parseInt(curDiv.getAttribute('startLeft')) < posX) && (parseInt(curDiv.getAttribute('startTop')) < posY) && ((parseInt(curDiv.getAttribute('startLeft')) + parseInt(curDiv.getAttribute('startWidth'))) > posX) && ((parseInt(curDiv.getAttribute('startTop')) + parseInt(curDiv.getAttribute('startHeight'))) > posY)) { activeCont = curDiv; break; } } if (activeCont && activeCont.id == myTargetDiv) { /** interface with Map API **/ var latlon = map.window2LatLon(posX, posY); create_marker(latlon, myCurrentTarget.getAttribute('id'), myCurrentTarget.getAttribute('html')); } } myCurrentTarget = null; myMouseDown = false; } /* mouseUp */ function mouseDown(ev) { ev = ev || window.event; var target = ev.target || ev.srcElement; myMouseDown = true; if (target.getAttribute('DragObj')) { return false; } } function dragdrop_init(targetDiv) { myTargetDiv = targetDiv; var args = new Array(); for (var i = 0; i < arguments.length; i++) { args.push(document.getElementById(arguments[i])); } CreateDragContainer.apply(this, args); myDragHelper = document.createElement('DIV'); myDragHelper.style.cssText = 'position:absolute;display:none;'; document.body.appendChild(myDragHelper); addToolboxEvent(document, 'onmousedown', mouseDown); addToolboxEvent(document, 'onmousemove', mouseMove); addToolboxEvent(document, 'onmouseup', mouseUp); } /** * \file generic_map.js * \brief WSN sensor node markers for maps * * $Revision: 1.2 $ * * Original Author: Sean M. Brennan * $Author: sean_m_brennan $ * * Created: December 12, 2007 * $Date: 2008/02/05 19:30:29 $ */ /* * Copyright 2007. Los Alamos National Security, LLC. This material * was produced under U.S. Government contract DE-AC52-06NA25396 for * Los Alamos National Laboratory (LANL), which is operated by Los * Alamos National Security, LLC, for the Department of Energy. The * U.S. Government has rights to use, reproduce, and distribute this * software. NEITHER THE GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY, * LLC, MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL * LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to * produce derivative works, such modified software should be clearly * marked, so as not to confuse it with the version available from LANL. * * Additionally, this program is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; version 2 of * the License. Accordingly, this program is distributed in the hope * it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. */ var DEBUG = false; var API = 'Google'; var StartLat = 35.871334; var StartLon = -106.326067; if (window._debug) { DEBUG = window._debug; } if (window._api) { setAPI(window._api); } if (window._start_lat) { StartLat = window._start_lat; } if (window._start_lon) { StartLon = window._start_lon; } /** enable inheritance **/ /** NB: inheritance is forbidden in MSN Virtual Earth ** use containers instead, ** but our own objects _must_ use 'extends' for MSN **/ Object.prototype.inheritsFrom = function(object) { for (var prop in object) { try { this[prop] = object[prop]; } catch(e) { } } for (var prop in object.prototype) { try { this.prototype[prop] = object.prototype[prop]; } catch(e) { } } delete object; } /**************************/ var map = null; var map_div = null; function generic_map_init(div_id) { if (checkBrowser()) { try { map_div = document.getElementById(div_id); map = new GenericMap(div_id); } catch(e) { writeMessage(e.message); } } else { alert("The " + API + " Maps API is not compatible with this browser."); } } function resize_map() { if (API == 'MSN') { var width = 0; var height = 0; if (typeof(window.innerWidth) == 'number') { width = ((window.innerWidth * 3) / 4) - 11; height = window.innerHeight - (86 + 4); } else if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientHeight) { width = ((document.documentElement.clientWidth * 3) / 4) - 11; height = document.documentElement.clientHeight - (86 + 4); } else if (document.body && document.body.clientWidth && document.body.clientHeight) { width = ((document.body.clientWidth * 3) / 4) - 11; height = document.body.clientHeight - (86 + 4); } if (width < 200) width = 200; if (height < 100) height = 100; map_div.style.width = width + 'px'; map_div.style.height = height + 'px'; map._map.Resize(width, height); } } if (API == 'Google') { window.onunload = GUnload; } // static methods if (API == 'MSN') { var markerMoving = false; var currentMarker = null; var oldCursor = ''; function markerDown(e) { if (e.elementID && map._map) { currentMarker = map._map.GetShapeByID(e.elementID); markerMoving = true; oldCursor = map_div.style.cursor; map_div.style.cursor = 'move'; map._map.vemapcontrol.EnableGeoCommunity(true); } } function markerMove(e) { // FIXME: MSN - ATLAS errors here for polygon var loc = map._map.PixelToLatLong(new VEPixel(e.mapX, e.mapY)); if (markerMoving && map._map) { map._map.HideInfoBox(currentMarker); currentMarker.SetPoints(loc); } } function markerUp(e) { if (markerMoving && map._map) { currentMarker = null; markerMoving = false; map_div.style.cursor = oldCursor; map._map.vemapcontrol.EnableGeoCommunity(false); } } } function checkBrowser() { if (!(document.createElement && document.getElementsByTagName)) return false; if (API == 'Google') { return GBrowserIsCompatible(); } else if (API == 'MSN') { return true; // TODO: MSN - detect supported browsers } } function getIconXOffset(position, offset) { if (API == 'Google') { return position.x - offset.x + 4; } else if (API == 'MSN') { return position.x - offset.x; } } function getIconYOffset(position, offset) { if (API == 'Google') { return position.y - offset.y + 30; } else if (API == 'MSN') { return position.y - offset.y; } } function hexColorRGB(hex) { var r = 0; var g = 0; var b = 0; var incr = 0; var mult = 1; if (hex[0] == '#') incr++; if (hex.length > 4) { r += parseInt(hex[incr + 0], 16) * 16; g += parseInt(hex[incr + 2], 16) * 16; b += parseInt(hex[incr + 4], 16) * 16; incr++; mult++; } r += parseInt(hex[incr + (0 * mult)], 16); g += parseInt(hex[incr + (1 * mult)], 16); b += parseInt(hex[incr + (2 * mult)], 16); return [r, g, b]; } function perimeterCenter(points) { if (API == 'Google') { return (new GBounds(corners)).mid(); } else if (API == 'MSN') { return map.GetCenter(); // FIXME: MSN - get center of bounding box ??? } } function setAPI(string) { if (string == 'Google' || string == 'MSN') { API = string; return true; } return false; } function GenericMap(div_name) { if (API == 'Google') { this._map = new GMap2(document.getElementById(div_name)); this._map.setCenter(new GLatLng(StartLat, StartLon), 18); this._map.addControl(new GSmallMapControl()); this._map.addControl(new GMapTypeControl()); this._map.setMapType(G_HYBRID_MAP); this._geo = new GClientGeocoder(); this._directions = new Array(); } else if (API == 'MSN') { var width = document.getElementById(div_name).offsetWidth; var height = document.getElementById(div_name).offsetHeight; this._map = new VEMap(div_name); this._map.LoadMap(); this._map.Resize(width, height); this._map.SetCenterAndZoom(new VELatLong(StartLat, StartLon), 16); this._map.SetMapStyle(VEMapStyle.Hybrid); this._map.AttachEvent('onmousedown', markerDown); this._map.AttachEvent('onmousemove', markerMove); this._map.AttachEvent('onmouseup', markerUp); this._map.AttachEvent('oncontextmenu', show_popup_menu); } } GenericMap.prototype.panTo = function(point) { if (API == 'Google') { this._map.panTo(point); } else if (API == 'MSN') { this._map.PanToLatLong(point); } } GenericMap.prototype.getCenter = function() { if (API == 'Google') { var ll = this._map.getCenter(); return new GenericLatLon(ll.lat(), ll.lng()); } else if (API == 'MSN') { var ll = this._map.GetCenter(); return new GenericLatLon(ll.Latitude, ll.Longitude); } } GenericMap.prototype.getZoom = function() { if (API == 'Google') { return this._map.getZoom(); } else if (API == 'MSN') { return this._map.GetZoomLevel(); } } GenericMap.prototype.getMaxZoom = function() { if (API == 'Google') { return this._map.getCurrentMapType().getMaximumResolution(); } else if (API == 'MSN') { return 30; // FIXME: MSN - find true max zoom } } GenericMap.prototype.getMinZoom = function() { if (API == 'Google') { return this._map.getCurrentMapType().getMinimumResolution(); } else if (API == 'MSN') { return 0; // FIXME: MSN - find true min zoom } } GenericMap.prototype.pixel2LatLon = function(position) { if (API == 'Google') { var ll = this._map.fromDivPixelToLatLng(position); return new GenericLatLon(ll.lat(), ll.lng()); } else if (API == 'MSN') { var ll = this._map.PixelToLatLong(position._point); return new GenericLatLon(ll.Latitude, ll.Longitude); } } GenericMap.prototype.latLon2Pixel = function(position) { if (API == 'Google') { var pt = this._map.fromLatLngToDivPixel(position); return new GenericPixel(pt.x, pt.y); } else if (API == 'MSN') { var pt = this._map.LatLongToPixel(position._latlon); return new GenericPixel(pt.x, pt.y); } } GenericMap.prototype.window2LatLon = function(x, y) { if (API == 'Google') { var ll = this._map.fromContainerPixelToLatLng(new GPoint(x, y)); return new GenericLatLon(ll.lat(), ll.lng()); } else if (API == 'MSN') { var ll = this._map.PixelToLatLong(new VEPixel(x, y)); // FIXME: MSN - off by icon size return new GenericLatLon(ll.Latitude, ll.Longitude); } } GenericMap.prototype.addItem = function(item) { if (API == 'Google') { return this._map.addOverlay(item); } else if (API == 'MSN') { return this._map.AddShape(item._item); } } GenericMap.prototype.removeItem = function(item) { if (API == 'Google') { return this._map.removeOverlay(item); } else if (API == 'MSN') { return this._map.DeleteShape(item._item); } } if (API == 'Google') { function geocoder_error(err_code) { switch (err_code) { case G_GEO_SUCCESS: return "Success"; case G_GEO_MISSING_ADDRESS: return "Missing Address."; case G_GEO_UNKNOWN_ADDRESS: return "Unknown Address Location."; case G_GEO_UNAVAILABLE_ADDRESS: return "Unavailable Address: due to legal or contractual reasons."; case G_GEO_BAD_KEY: return "Bad API Key."; case G_GEO_TOO_MANY_QUERIES: return "Too Many Queries, Quota Exceeded."; case G_GEO_SERVER_ERROR: return "Server Error."; } return "Unknown error (" + err_code + ")."; } } function get_route_error(dir) { if (API == 'Google') return geocoder_error(dir.getStatus().code); else if (API == 'MSN') return ''; // FIXME } function adjust_route(marker, dir) { if (API == 'Google') { marker._path = dir.getPolyline(); // TODO: copy polyline, dir.clear() marker.setLatLng(dir.getMarker(0).getLatLng()); for (var i = 0; i < dir.getNumGeocodes(); i++) dir.getMarker(i).remove(); } else if (API == 'MSN') { // FIXME } } GenericMap.prototype.loadRoute = function(latlons, color, success, failure, path) { if (API == 'Google') { var dir = new GDirections(this._map); var request = new Array(); for (var i = 0; i < latlons.length; i++) request.push(latlons[i].getLat() + ',' + latlons[i].getLon()); dir.loadFromWaypoints(request, {getPolyline: true, preserveViewport: true}); this._directions.push(dir); GEvent.addListener(dir, "load", success); GEvent.addListener(dir, "error", failure); GEvent.addListener(dir, "addoverlay", path); } else if (API == 'MSN') { var waypts = new Array(); for (var i = 0; i < latlons.length; i++) waypts.push(latlons[i]._latlon); var options = new VERouteOptions; options.DrawRoute = true; options.SetBestMapView = false; options.ShowDisambiguation = true; map.GetDirections(waypts); alert("MSN Virtual Earth does not support multiple routes."); // Also, cannot extract polyline either } } GenericMap.prototype.geoSearch = function(search) { if (API == 'Google') { this._geo.getLocations(search, function (result) { if (result.Status.code == G_GEO_SUCCESS) { if (result.Placemark.length > 1) { writeMessage('Did you mean:'); for (var i = 0; i < result.Placemark.length; i++) { var p = result.Placemark[i].Point.coordinates; writeMessage((i+1) + ": " + result.Placemark[i].address + ""); } } else { var p = result.Placemark[0].Point.coordinates; found_location(p[1], p[0]); } } else { // error var reason = geocoder_error(result.Status.code); writeMessage('Could not find "' + search + '" ' + reason); } } ); } else if (API == 'MSN') { try { this._map.Find(null, search); } catch(e) { writeMessage(e.message); } } } function GenericLatLon(lat, lon) { if (API == 'Google') { this.inheritsFrom(new GLatLng(lat, lon)); } else if (API == 'MSN') { this._latlon = new VELatLong(lat, lon); } } GenericLatLon.prototype.getLat = function() { if (API == 'Google') { return this.lat(); } else if (API == 'MSN') { return this._latlon.Latitude; } } GenericLatLon.prototype.getLon = function() { if (API == 'Google') { return this.lng(); } else if (API == 'MSN') { return this._latlon.Longitude; } } GenericLatLon.prototype.toString = function() { if (API == 'Google') { return '(' + this.lat() + ', ' + this._latlon.lng() + ')'; } else if (API == 'MSN') { return '(' + this._latlon.Latitude + ', ' + this._latlon.Longitude + ')'; } } function GenericPixel(x, y) { if (API == 'Google') { this.inheritsFrom(new GPoint(x, y)); } else if (API == 'MSN') { this._point = new VEPixel(x, y); } } GenericPixel.prototype.getX = function() { if (API == 'Google') { return this.x; } else if (API == 'MSN') { return this._point.x; } } GenericPixel.prototype.getY = function() { if (API == 'Google') { return this.y; } else if (API == 'MSN') { return this._point.y; } } function GenericPolyline(latlons, color) { if (API == 'Google') { GPolyline.call(this, latlons, color, 5, 0.5); // color, weight, opacity } else if (API == 'MSN') { var vertices = new Array(); for (var i = 0; i < latlons.length; i++) vertices.push(latlons[i]._latlon); this._item = new VEShape(VEPolyline, vertices); } } if (API == 'Google') { GenericPolyline.prototype = new GPolyline(new GLatLng(0,0)); GenericPolyline.prototype.initialize = function(a) { GPolyline.prototype.initialize.call(this, a); } GenericPolyline.prototype.redraw = function(force) { GPolyline.prototype.redraw.call(this, force); } GenericPolyline.prototype.remove = function() { GPolyline.prototype.remove.call(this); } } function GenericMarker(latlon, iconSrc, offset) { if (API == 'Google') { if (iconSrc != null) { var icon = new GIcon(G_DEFAULT_ICON, iconSrc); icon.shadow = ""; if (offset != null) { icon.iconAnchor = offset; } GMarker.call(this, latlon, {icon: icon, draggable: true}); // this.inheritsFrom(new GMarker(latlon, {icon: icon, draggable: true})); } else { GMarker.call(this, latlon, {draggable: true}); // this.inheritsFrom(new GMarker(latlon, {draggable: true})); } } else if (API == 'MSN') { this._item = new VEShape(VEShapeType.Pushpin, latlon._latlon); if (iconSrc != null) { this._item.SetCustomIcon(iconSrc); // FIXME: MSN - anchor is incorrect (Pushpin ignores SetIconAnchor) // use DOM styles embedding var ctr = map.latLon2Pixel(latlon); var anchor = new GenericPixel(ctr.getX() + 100, ctr.getY() + 100); if (offset) { anchor = new GenericPixel(ctr.getX() + offset.getX(), ctr.getY() + offset.getY()); } var anchorLatLon = map.pixel2LatLon(anchor); this._item.SetIconAnchor(anchorLatLon._latlon); } } } if (API == 'Google') { GenericMarker.prototype = new GMarker(new GLatLng(0,0)); GenericMarker.prototype.initialize = function(a) { GMarker.prototype.initialize.call(this, a); } GenericMarker.prototype.redraw = function(force) { GMarker.prototype.redraw.call(this, force); } GenericMarker.prototype.remove = function() { GMarker.prototype.remove.call(this); } } GenericMarker.prototype.addListener = function(type, func) { if (API == 'Google') { GEvent.addListener(this, type, func); } else if (API == '') { addToolboxEvent(this._item, 'on' + type, func); } } GenericMarker.prototype.getLatLon = function() { if (API == 'Google') { var latlon = this.getLatLng(); return new GenericLatLon(latlon.lat(), latlon.lng()); } else if (API == 'MSN') { var latlon = (this._item.GetPoints())[0]; return new GenericLatLon(latlon.Latitude, latlon.Longitude); } } GenericMarker.prototype.getOverOutString = function() { return 'onmouseover="markers[' + this._mrkrIdx + '].toggleOver()"' + 'onmouseout ="markers[' + this._mrkrIdx + '].toggleOut()"'; } GenericMarker.prototype.setImage = function(image) { if (API == 'Google') { GMarker.prototype.setImage.call(this, image); } else if (API == 'MSN') { this._item.SetCustomIcon(image); } } GenericMarker.prototype.show = function() { this.hidden = false; } GenericMarker.prototype.hide = function() { this.hidden = true; } function GenericPolygon(latlon, strokeColor, fillColor, corners) { this._centerPoint = latlon; this._strokeColor = strokeColor || '#000000'; this._fillColor = fillColor || '#ffffff'; this._markers = new Array(); if (corners) { this._points = corners; } else { // square this._points = new Array(); if (map != null) { var corner; var cornerLatLon; var cornerLen = (obstrSide / 2); var point = map.latLon2Pixel(this._centerPoint); // start at top, left corner = new GenericPixel(point.getX() - cornerLen, point.getY() - cornerLen); cornerLatLon = map.pixel2LatLon(corner); this._points.push(cornerLatLon); // go counterclockwise (for KML compatibility) corner = new GenericPixel(point.getX() - cornerLen, point.getY() + cornerLen); cornerLatLon = map.pixel2LatLon(corner); this._points.push(cornerLatLon); corner = new GenericPixel(point.getX() + cornerLen, point.getY() + cornerLen); cornerLatLon = map.pixel2LatLon(corner); this._points.push(cornerLatLon); corner = new GenericPixel(point.getX() + cornerLen, point.getY() - cornerLen); cornerLatLon = map.pixel2LatLon(corner); this._points.push(cornerLatLon); // return to top, left corner = new GenericPixel(point.getX() - cornerLen, point.getY() - cornerLen); cornerLatLon = map.pixel2LatLon(corner); this._points.push(cornerLatLon); } } if (API == 'Google') { this._centerMark = new GenericMarker(this._centerPoint, obstrBodyImg); this._centerMark._obstr = this; this._centerMark.addListener('dragend', function() { if (this._obstr) { this._obstr.move(); } }); if (map != null) { map.addItem(this._centerMark); this.changePointMarkers(); map.addItem(this); } GPolygon.call(this, this._points, this._strokeColor, 2, 1, this._fillColor, 1); } else if (API == 'MSN') { var vertices = new Array(); for (var i = 0; i < this._points.length; i++) vertices.push(this._points[i]._latlon); this._item = new VEShape(VEShapeType.Polygon, vertices); this._item.SetCustomIcon(obstrBodyImg); var ctr = map.latLon2Pixel(this._centerPoint); var anchor = new GenericPixel(ctr.getX(), ctr.getY() - 15); var anchorLatLon = map.pixel2LatLon(anchor); this._item.SetIconAnchor(anchorLatLon._latlon); var strokeRGB = hexColorRGB(this._strokeColor); this._item.SetLineColor(new VEColor(strokeRGB[0], strokeRGB[1], strokeRGB[2], 1.0)); this._item.SetLineWidth(2); var fillRGB = hexColorRGB(this._fillColor); this._item.SetFillColor(new VEColor(fillRGB[0], fillRGB[1], fillRGB[2], 1.0)); // FIXME: MSN - uncomment when markers are fixed // this.changePointMarkers(); } } if (API == 'Google') { GenericPolygon.prototype = new GPolygon(new Array(new GLatLng(0,0))); GenericPolygon.prototype.initialize = function(a) { GPolygon.prototype.initialize.call(this, a); GenericMarker.prototype.initialize.call(this._centerMark, a); } GenericPolygon.prototype.redraw = function(force) { GPolygon.prototype.redraw.call(this, force); GenericMarker.prototype.redraw.call(this._centerMark, force); } GenericPolygon.prototype.remove = function() { map.removeItem(this._centerMark); for (mark in this._markers) map.removeItem(mark); GPolygon.prototype.remove.call(this); } // FIXME: Google - full deletion of obstructions } GenericPolygon.prototype.refresh = function() { if (API == 'Google') { map.removeItem(this._centerMark); map.addItem(this._centerMark); map.removeItem(this); GPolygon.call(this, this._points, this._strokeColor, 2, 1, obstrColor, 1); map.addItem(this); } } GenericPolygon.prototype.getOverOutString = function() { return 'onmouseover="markers[' + this._mrkrIdx + '].toggleOver()"' + 'onmouseout ="markers[' + this._mrkrIdx + '].toggleOut()"'; } GenericPolygon.prototype.copy = function() { return new GenericPolygon(this._centerPoint, this._strokeColor, this._fillColor, this._points); } GenericPolygon.prototype.move = function() { if (API == 'Google') { var newCtr = this._centerMark.getLatLon(); var ctrPt = map.latLon2Pixel(newCtr); var oldCtrPt = this._centerPoint; var ctrDiff = new GenericLatLon(newCtr.getLat() - oldCtrPt.getLat(), newCtr.getLon() - oldCtrPt.getLon()); this._centerPoint = newCtr; var vertices = new Array(); for (var i = 0; i < this._points.length; i++) { var vert = this._points[i]; var latlon = new GenericLatLon(vert.getLat() + ctrDiff.getLat(), vert.getLon() + ctrDiff.getLon()); vertices.push(latlon); } this._points.length = 0; this._points = vertices; this.changePointMarkers(); this.refresh(); } } // FIXME: MSN - resize (using corner markers) is unavailable GenericPolygon.prototype.resize = function() { this._points.length = 0; for (var i = 0; i < this._markers.length; i++) this._points.push(this._markers[i].getLatLon()); this._points.push(this._markers[0].getLatLon()); this.refresh(); } // FIXME: MSN - corner markers are misaligned GenericPolygon.prototype.changePointMarkers = function() { for (var i = 0; i < this._markers.length; i++) map.removeItem(this._markers[i]); this._markers.length = 0; for (var i = 0; i < (this._points.length - 1); i++) { var marker = new GenericMarker(this._points[i], obstrCornerImg, new GenericPixel(10, 32)); marker._obstr = this; this._markers.push(marker); map.addItem(marker); marker.addListener("dragend", function() { if (this._obstr) { this._obstr.resize(); } }); } } GenericPolygon.prototype.toggleOver = function() { if (API == 'Google') { this._centerMark.setImage(anyOn); } else if (API == 'MSN') { this._item.SetCustomIcon(anyOn); } } GenericPolygon.prototype.toggleOut = function() { if (API == 'Google') { this._centerMark.setImage(obstrBodyImg); } else if (API == 'MSN') { this._item.SetCustomIcon(obstrBodyImg); } } GenericPolygon.prototype.getCenter = function() { return this._centerPoint; } GenericPolygon.prototype.setCenter = function(pt) { this.setLatLng(pt); } GenericPolygon.prototype.getLatLon = function() { return this._centerPoint; } GenericPolygon.prototype.setLatLon = function(pt) { this._centerPoint = pt; this._centerMark.setLatLng(this._centerPoint); this.move(); } GenericPolygon.prototype.show = function() { this.hidden = false; for (mark in this._markers) mark.show(); this._centerMark.show(); } GenericPolygon.prototype.hide = function() { this.hidden = true; for (mark in this._markers) mark.hide(); this._centerMark.hide(); } /** * \file toolbox.js * \brief WSN sensor node markers for maps * * $Revision: 1.7 $ * * Original Author: Sean M. Brennan * $Author: sean_m_brennan $ * * Created: December 12, 2007 * $Date: 2008/02/05 19:30:31 $ */ /* * Copyright 2007. Los Alamos National Security, LLC. This material * was produced under U.S. Government contract DE-AC52-06NA25396 for * Los Alamos National Laboratory (LANL), which is operated by Los * Alamos National Security, LLC, for the Department of Energy. The * U.S. Government has rights to use, reproduce, and distribute this * software. NEITHER THE GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY, * LLC, MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL * LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to * produce derivative works, such modified software should be clearly * marked, so as not to confuse it with the version available from LANL. * * Additionally, this program is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; version 2 of * the License. Accordingly, this program is distributed in the hope * it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. */ // requires generic_api.js var xml = ""; var user = "guest"; var pwd = ""; var xmlDoc = null; var waypoints = []; var way_markers = []; var currentSource = null; var numNodes = 0; var nodes = []; var numSources = 0; var sources = []; var numObstructions = 0; var obstructions = []; var numMarkers = 0; var markers = []; var anyOn = "img/node_over.png"; var nodeOff = "img/node.png"; var sourceOff = "img/source.png"; var sourcePathColor = '#1616ff'; // '#a5ef8d'; // green var obstrCornerImg = "img/obstruction_corner.png"; var obstrBodyImg = "img/obstruction.png"; var obstrColor = '#ffea00'; var obstrSide = 24; // pixels /** SensorNode object, extends GenericMarker **/ function SensorNode(name, num, latlon, html) { this._name = name; this._mrkrIdx = num; // FIXME: parse description html this.inheritsFrom(new GenericMarker(latlon, nodeOff)); } SensorNode.prototype.toggleOver = function() { this.setImage(anyOn); } SensorNode.prototype.toggleOut = function() { this.setImage(nodeOff); } SensorNode.prototype.getFormString = function() { return ' ' + ''; } SensorNode.prototype.processForm = function(form) { // FIXME: fields for forms for editing this._battery = form.battery; } SensorNode.prototype.getDescriptionString = function() { return '' + this._battery + ''; } /** end SensorNode class **/ /****************************/ /** Source object, extends GenericMarker **/ function Source(name, num, latlon, html) { this._name = name; this._mrkrIdx = num; // FIXME: parse description html this.inheritsFrom(new GenericMarker(latlon, sourceOff)); this.addListener('click', function() { // only works for Google show_popup_menu(this); return false; }); } // FIXME: if move, also move _path Source.prototype.toggleOver = function() { this.setImage(anyOn); } Source.prototype.toggleOut = function() { this.setImage(sourceOff); } Source.prototype.getFormString = function() { return ' '; } Source.prototype.processForm = function(form) { this._type = form.type; } Source.prototype.getDescriptionString = function() { return '' + this._type + ''; } /** end Source class **/ function hide_popup_menu() { currentSource = null; document.getElementById('popupmenu').style.display = 'none'; document.getElementById('dynamicmenu').innerHTML = 'Create a path on roads' + '
' + 'Create a path anywhere' } function show_popup_menu(marker) { currentSource = marker; var popupPosition = marker.getLatLon(); var x, y; if (API == 'Google') { x = 0; // FIXME: menu alignment -> infoWindow instead?? y = 0; } else if (API == 'MSN') { popupPosition = new GenericLatLon(marker.view.LatLong.Latitude, marker.view.LatLong.Longitude); x = map._map.GetLeft(); y = map._map.GetTop(); } var corner = map.latLon2Pixel(popupPosition); var menu = document.getElementById('popupmenu'); menu.style.display = 'block'; menu.style.left = corner.getX() + x; menu.style.top = corner.getY() + y; } function follow_roads() { way_markers.length = 0; way_markers.push(currentSource); document.getElementById('popupmenu').style.display = 'none'; document.getElementById('dynamicmenu').innerHTML = 'Add to this road path' + '
' + 'End this road path'; } function add_roads() { way_markers.push(currentSource); document.getElementById('popupmenu').style.display = 'none'; } function route_loaded() { for (var i = 1; i < way_markers.length; i++) way_markers[i].remove(); // FIXME make more complete (incl this._path) } function route_error() { writeMessage("Route error: " + get_route_error(this)); } function route_path() { adjust_route(way_markers[0], this); } function stop_roads() { var waypoints = new Array(); way_markers.push(currentSource); for (var i = 0; i < way_markers.length; i++) waypoints.push(way_markers[i].getLatLon()); map.loadRoute(waypoints, sourcePathColor, route_loaded, route_error, route_path); hide_popup_menu(); } function make_path() { way_markers.length = 0; way_markers.push(currentSource); document.getElementById('popupmenu').style.display = 'none'; document.getElementById('dynamicmenu').innerHTML = 'Add to this path' + '
End this path'; } function add_path() { way_markers.push(currentSource); document.getElementById('popupmenu').style.display = 'none'; } function stop_path() { var waypoints = new Array(); var headSource = way_markers[0]; waypoints.push(headSource.getLatLon()); for (var i = 1; i < way_markers.length; i++) { waypoints.push(way_markers[i].getLatLon()); way_markers[i].remove(); } waypoints.push(currentSource.getLatLon()); currentSource.remove(); var line = new GenericPolyline(waypoints, sourcePathColor); headSource._path = line; map.addItem(line); hide_popup_menu(); } /************************/ /** Obstruction object, extends GenericPolygon **/ function Obstruction(name, num, latlon, html, corners) { var lineColor = '#000000'; this._name = name; this._mrkrIdx = num; // FIXME: parse description html this._obstrHeight = 10; // i.e. ~two stories tall if (API == 'Google') GenericPolygon.call(this, latlon, lineColor, obstrColor, corners); else if (API == 'MSN') this.inheritsFrom(new GenericPolygon(latlon, lineColor, obstrColor, corners)); } if (API == 'Google') { Obstruction.prototype = new GenericPolygon(new Array(new GenericLatLon(0,0))); Obstruction.prototype.initialize = function(a) { GenericPolygon.prototype.initialize.call(this, a); } Obstruction.prototype.redraw = function(force) { GenericPolygon.prototype.redraw.call(this, force); } Obstruction.prototype.remove = function() { GenericPolygon.prototype.remove.call(this); } } Obstruction.prototype.getFormString = function(name, num) { return ' ' + '

Alternatively, load an Obstructions file:
' + '' + '' + '

'; } Obstruction.prototype.processForm = function(form) { this._obstrHeight = form.height; } Obstruction.prototype.getDescriptionString = function() { return '' + this._obstrHeight + ''; } /** end Obstruction class **/ /*****************************/ /** Modify scenario objects **/ function edit_marker(name, num) { if (markers[num] != null) { document.getElementById(name).innerHTML = '' + ' ' + '' + name + '
' + '
' + markers[num].getFormString(name, num) + '' + '
'; } } function remove_marker(name, num) { map.removeItem(markers[num]); markers[num] = null; document.getElementById(name).innerHTML = ''; } function commit_edit(form, name, num) { markers[num].processForm(form); close_edit(name, num); } function close_edit(name, num) { if (markers[num] != null) { document.getElementById(name).innerHTML = '' + ' ' + '' + name + ''; } } function load_obstruction(form, name, num) { remove_marker(name, num); form.submit(); } /*******************************/ /** Search for a location **/ function found_location(lat, lng) { var point = new GenericLatLon(lat, lng); map.panTo(point); } function geo_search() { map.geoSearch(document.getElementById("geosearch").value); } /*****************************/ function create_marker(latlon, name, html, pts) { var marker = null; try { var num = 0; if (name.substring(0, 4) == 'Node') { num = ++numNodes; if (name.length == 4) { name += ' ' + num; } marker = new SensorNode(name, numMarkers, latlon, html); nodes[num - 1] = marker; } else if (name.substring(0, 6) == 'Source') { num = ++numSources; if (name.length == 6) { name += ' ' + num; } marker = new Source(name, numMarkers, latlon, html); sources[num - 1] = marker; } else if (name.substring(0, 11) == 'Obstruction') { num = ++numObstructions; if (name.length == 11) { name += ' ' + num; } marker = new Obstruction(name, numMarkers, latlon, html, pts); obstructions[num - 1] = marker; } else return null; var div = document.createElement("div"); div.setAttribute("id", name); div.setAttribute("style", "text-decoration:none"); writeMessage('Added ' + name + ' at ' + marker.getLatLon().toString()); map.addItem(marker); markers[numMarkers++] = marker; document.getElementById("deployment").appendChild(div); close_edit(name, numMarkers-1); } catch(e) { writeMessage("Error:" + e.message); } return marker; } function goto_xml() { // FIXME: modify for WSN_XML + paths if (numMarkers == 0) { writeMessage("Current deployment is empty."); return false; } var ctr = map.getCenter(); var maxZoom = map.getMaxZoom(); var minZoom = map.getMinZoom(); var factor = maxZoom - map.getZoom() - minZoom; if (factor == 0) { factor = 0.5; } else if (factor < 0) { factor = 1.0 / (0.0 - factor); } var fraction = ((factor * 1.0) / (maxZoom * 1.0)) * 1.5; var power = 1.0 + fraction; var range = Math.pow((factor * 5), power) * 100; xml = ' ' + ' ' + ctr.lng() + '' + ' ' + ctr.lat() + '' + ' ' + range + '' + ' 0.0' + ' 0.0' + ' '; for (var i = 0; i < numNodes; i++) { var latlon = nodes[i].getLatLon(); xml += ' ' + ' Node ' + (i+1) + '' + ' #sensorPlacemark' + ' ' + nodes[i].getDescriptionString() + '' + ' ' + ' ' + latlon.lng() + ',' + latlon.lat() + ',0' + ' ' + ' '; } for (var i = 0; i < numSources; i++) { var latlon = sources[i].getLatLon(); xml += ' ' + ' Source ' + (i+1) + '' + ' #sourcePlacemark' + ' ' + sources[i].getDescriptionString() + '' + ' ' + ' ' + latlon.lng() + ',' + latlon.lat() + ',0' + ' ' + ' '; } for (var i = 0; i < numObstructions; i++) { var latlons = obstructions[i]._points; xml += ' ' + ' Obstruction ' + (i+1) + '' + ' #obstructionPolygon' + ' ' + obstructions[i].getDescriptionString() + '' + ' ' + ' 1' + ' relativeToGround' + ' ' + ' ' + ' '; for (var j = 0; j < latlons.length; j++) { xml += ' ' + latlons[j].lng() + ',' + latlons[j].lat() + ',' + obstructions[i]._obstrHeight + ''; } xml += ' ' + ' ' + ' ' + ' ' + ' '; } document.getElementById("fileXml").value = xml; writeMessage("Saving " + document.getElementById("fileName").value + "."); if (DEBUG) { writeMessage(xml.toString()); } writeMessage("Queuing simulation; Switching to GoogleEarth."); document.getElementById("file").submit; return true; } function load_configuration() { if (user == "guest") { writeMessage("File loading is disabled for guest users."); return false; } var filename = document.getElementById("fileName").value; var uri = "load_wsn_xml.php?filename=" + filename; writeMessage("Loading " + filename); if (document.implementation && document.implementation.createDocument) { xmlDoc = document.implementation.createDocument("", "", null); xmlDoc.load(uri); xmlDoc.onload = load_xmldoc; } else { xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = false; xmlDoc.load(uri); load_xmldoc(); } } function load_xml_string(string) { try { xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = false; xmlDoc.loadXML(string); } catch(e) { var parser = new DOMParser(); xmlDoc = parser.parseFromString(string, "text/xml"); } load_xmldoc(); } function load_xmldoc() { // FIXME: modify for WSN_XML + paths var markers = xmlDoc.getElementsByTagName("Placemark"); for (var i = 0; i < markers.length; i++) { var coord_node = markers[i].getElementsByTagName("coordinates")[0].childNodes[0]; if (coord_node == null) { continue; } var coords = coord_node.nodeValue.split(",", 3); var lng = parseFloat(coords[0]); var lat = parseFloat(coords[1]); var point = new GenericLatLon(lat, lng); var html = ""; var label = ""; var html_node = markers[i].getElementsByTagName("description")[0].childNodes[0]; if (html_node) { html += html_node.nodeValue; } var label_node = markers[i].getElementsByTagName("name")[0].childNodes[0]; if (label_node) { label += label_node.nodeValue; } create_marker(point, label, html); } var markers = xmlDoc.getElementsByTagName("Polygon"); for (var i = 0; i < markers.length; i++) { var coord_node = markers[i].getElementsByTagName("coordinates")[0].childNodes[0]; if (coord_node == null) { continue; } var corners = new Array(); var points = coord_node.nodeValue.split("\n"); // FIXME var alt = 0; var num_alt = 0; for (var corner in points) { var coords = corner.split(",", 3); var lng = parseFloat(coords[0]); var lat = parseFloat(coords[1]); alt += parseFloat(coords[2]); num_alt++; var point = new GenericLatLon(lat, lng); corners.push(point); } var centerPt = perimeterCenter(corners); var html = ""; var label = ""; var html_node = markers[i].getElementsByTagName("description")[0].childNodes[0]; if (html_node) { html += html_node.nodeValue; } var label_node = markers[i].getElementsByTagName("name")[0].childNodes[0]; if (label_node) { label += label_node.nodeValue; } var marker = create_marker(centerPt, label, html, corners); marker._obstrHeight = alt / num_alt; marker._points.length = 0; marker._points = corners; marker.changePointMarkers(); } } function clear_map() { if (markers.length > 0 && confirm('Clear the current deployment?')) { for (var i = 0; i < markers.length; i++) { if (markers[i]._name.substring(0, 4) == 'Node' || markers[i]._name.substring(0, 6) == 'Source') { map.removeItem(markers[i]); } } numNodes = 0; nodes.length = 0; numSources = 0; sources.length = 0; numObstructions = 0; for (var i = 0; i < obstructions.length; i++) obstructions[i].remove(); obstructions.length = 0; numMarkers = 0; markers.length = 0; xml = ""; document.getElementById("deployment").innerHTML = ""; } } function map_toolbox_init() { /** generic_map.js **/ generic_map_init('map'); /** dragdrop.js **/ dragdrop_init('map', 'nodes', 'sources', 'obstructions'); if (xml != '') load_xml_string(xml); hide_popup_menu(); }