UNPKG

dashboard

Version:

Create dashboards with gadgets on node.js

500 lines (409 loc) 15.8 kB
<?xml version="1.0" encoding="UTF-8" ?> <Module> <ModulePrefs title="Sky Viewport" height="400" scrolling="true"> <Require feature="dynamic-height"/> <Require feature="opensocial-0.8"/> <Require feature="minimessage"/> </ModulePrefs> <Content type="html"><![CDATA[ <script src="http://maps.google.com/jsapi?key=ABQIAAAAKYHb1B3NpT-mpL4s83EIgRSop_PCxtS7_vOEwBFafrYxod0JxBQK6BarsnpmKY7-BFhZ1QAd3zSaLg" type="text/javascript"></script> <script src="http://sky.astro.washington.edu/gadgets/js/gDataInterface.js" type="text/javascript"></script> <script src="http://students.washington.edu/csayres/widgetlib1.js" type="text/javascript"></script> <script src="http://sky.astro.washington.edu/gadgets/js/astroObjectLib.js" type="text/javascript"></script> <script type="text/javascript"> // run some triggers just in case it took us a while to start up and there are already some public vars we need to react to // refreshKMLFromList("VP_Point_List", _KMLPointList); // Writes to the console if debug (global) is true function debugLog(msg){ if ((debug === true) && (window.console && console.log)) { console.log(GADGET_NAME + ": " + msg); } return; } var vpe = null; // CONSTANTS var GADGET_NAME = "ViewportSky" + "_" + Math.floor(Math.random()*100000+1).toString() debug = true; function init(){ //debugger; vpe = new ViewportEarth(); gadgets.window.adjustHeight(); } function ViewportEarth() { var my = new Object(); // CONSTANTS var DEFAULT_NAMESPACE = "NS1", MM_TIMER_DURATION = 4, TIMER_VIEWCHANGEEND = 200; // ms to wait to trigger the ge viewchangeend event // PRIVATE var _namespaceList = [ DEFAULT_NAMESPACE ]; // list of our current Namespaces. Just init with the default var di = new gDataInterface(GADGET_NAME, DEFAULT_NAMESPACE); // make dataInterface object, init with default var miniMsg = new gadgets.MiniMessage();// make MiniMessage object var msg = miniMsg.createStaticMessage("Attempting to register gadget..."); var triggerArray = [ ["KML_List", showKML], // ["Dataset_1", updateSelectedPoints], // ["DatasetList", updateDatasetList] ]; ["VP_Point_List", function(){refreshKMLFromList("VP_Point_List", _KMLPointList);} ], ["VP_Speed", setFlyToSpeed], ["VP_Coord", moveMap], ["VP_Coord_Center", moveMapCenter], ["DatasetList", updateDatasetList] ]; di.registerMe( { gadgetName : GADGET_NAME, namespaceList : _namespaceList, variableList : [ "VP_Coord_Center", "VP_Coord", "KML_List", "VP_Point_List", "VP_Current_Bounds", "VP_Speed", "DatasetList" ], triggerList : triggerArray, successCallback : registrationSuccess, failureCallback : registrationFailure } ); // Callback after successful registration function registrationSuccess(){ debugLog('Registration successful'); if (msg) { miniMsg.dismissMessage(msg); // free up msg msg = null; miniMsg.createTimerMessage("Registration Succesful.", MM_TIMER_DURATION); } } // Callback after a failure of registration // displays message showing failure function registrationFailure(){ debugLog('Registration FAILED!'); miniMsg.dismissMessage(msg); miniMsg.createDismissibleMessage("Unable to register gadget.\nWe cannot communicate with other gadgets."); } // private Point List // first make the list item constructor function KMLListItem(){} KMLListItem.prototype = { KMLObj : null, listItemId : -1, isPlotted : false, id : null, }; var _KMLPointList = []; var tidsViewchangeend = []; // array of timer IDs for ge viewchangeend event var iconUrlStyles = { grey: { url: "http://sky.astro.washington.edu/gadgets/images/target_grey.png", kmlStyle: null }, red: { url: "http://sky.astro.washington.edu/gadgets/images/target_red.gif", kmlStyle: null }, green: { url: "http://sky.astro.washington.edu/gadgets/images/target_green.gif", kmlStyle: null }, yellow: { url: "http://sky.astro.washington.edu/gadgets/images/target_yellow.gif", kmlStyle: null }, blue: { url: "http://sky.astro.washington.edu/gadgets/images/target_blue.png", kmlStyle: null } }; // INIT Functions // init google earth (ge) var ge = null; // the google earth object is within the viewport scope google.load("earth", "1"); google.setOnLoadCallback(initGE); function updateDatasetList(){ var list = di.readVariable(DEFAULT_NAMESPACE, "DatasetList").slice(0); // copy array // register trigger to this dataset variable so updates happen when it changes var datasetName = list[0]; di.registerVariable(DEFAULT_NAMESPACE, datasetName, null); //di.registerTrigger(DEFAULT_NAMESPACE, datasetName, function(){plotAllFromDataset(datasetName);}); di.registerTrigger(DEFAULT_NAMESPACE, datasetName, function(){updatePlacemarkStyles(datasetName);}); // TODO: need to unregister the previous dataset! } function initGE() { google.earth.createInstance('sky_map', initCB, failureCB); } // callback on successful creation of ge plugin instance function initCB(instance) { ge = instance; ge.getWindow().setVisibility(true); ge.getOptions().setMapType(ge.MAP_TYPE_SKY); ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO); ge.getOptions().setStatusBarVisibility(true); // Add event listeners google.earth.addEventListener(ge.getView(), "viewchangeend", function(){ // write the new VP bounds to the public variable // TODO: This will need a timer, because the viewchangeend event fires so often when dragging slowly. // We need to make sure that we arent writing the current bounds more often than once every 250ms or so writeCurrentBounds(); }); // fill the iconUrlStyles variable with actual KML styles createIconStyles(iconUrlStyles); // we can implement this stuff later if we want... //Initialize map to Sombrero Galaxy // setTimeout(function() { // var oldFlyToSpeed = ge.getOptions().getFlyToSpeed(); // ge.getOptions().setFlyToSpeed(.2); // Slow down the camera flyTo speed. // var lookAt = ge.getView().copyAsLookAt(ge.ALTITUDE_RELATIVE_TO_GROUND); // lookAt.set(-11.623055555555556, 9.997500000000002, 0,ge.ALTITUDE_RELATIVE_TO_GROUND, 262.87, 0, 6039.328125684229); // ge.getView().setAbstractView(lookAt); // ge.getOptions().setFlyToSpeed(oldFlyToSpeed); // }, 1000); // Start the zoom-in after one second. } function failureCB(errorCode) { alert("*** Error initializing google earth plugin ***"); } // METHODS // Sets the flytospeed between 0 and 5 function setFlyToSpeed() { var speed = parseFloat(di.readVariable(DEFAULT_NAMESPACE, "VP_Speed")); if (!isNaN(speed)) { if ((speed >= 0) && (speed <= 5)) { ge.getOptions().setFlyToSpeed(speed); // fastest speed before ge.SPEED_TELEPORT } } } // Slews map to point (center) at new coordinate // TODO: with range? or bounding box? function moveMap (){ var coord = di.readVariable(DEFAULT_NAMESPACE, "VP_Coord"); var lon = coord.getLongitude(); var lat = coord.getLatitude(); //alert("RA: " + ra + "\nDEC: " + dec); // check that ra and dec are numbers if (!isNaN(lon) && !isNaN(lat)){ var lookAt = ge.createLookAt(''); lookAt.setLatitude(lat); lookAt.setLongitude(lon); lookAt.setAltitude(0); lookAt.setHeading(0); lookAt.setRange(7000.0); ge.getView().setAbstractView(lookAt); } } // Slews map to point (center) at new coordinate // TODO: with range? or bounding box? function moveMapCenter (){ var coord = di.readVariable(DEFAULT_NAMESPACE, "VP_Coord_Center"); var lon = coord.getLongitude(); var lat = coord.getLatitude(); //alert("RA: " + ra + "\nDEC: " + dec); // check that ra and dec are numbers if (!isNaN(lon) && !isNaN(lat)){ var lookAt = ge.createLookAt(''); lookAt.setLatitude(lat); lookAt.setLongitude(lon); lookAt.setAltitude(0); lookAt.setHeading(0); lookAt.setRange(ge.getView().copyAsLookAt(ge.ALTITUDE_RELATIVE_TO_GROUND).getRange()); ge.getView().setAbstractView(lookAt); } } writeCurrentBounds = function(){ // we need to wait a few ms so we don't trigger this event too often if (tidsViewchangeend.length !== 0){ // if the timer was already set, then clear them to reset them. clearTimerArray(tidsViewchangeend); } // now there is no timer set // so make one var tid = setTimeout(function(){ boxBounds = ge.getView().getViewportGlobeBounds(); topLeft = new UW.astro.CelestialCoordinate(0,0); topLeft.setLongitude(boxBounds.getWest()); topLeft.setLatitude(boxBounds.getNorth()); bottomRight = new UW.astro.CelestialCoordinate(0,0); bottomRight.setLongitude(boxBounds.getEast()); bottomRight.setLatitude(boxBounds.getSouth()); curBounds = [topLeft, bottomRight]; // 2-element array of CelestialCoordinates. [topLeft, bottomRight] di.writeVariable(DEFAULT_NAMESPACE, "VP_Current_Bounds", curBounds); }, TIMER_VIEWCHANGEEND); // add the new timer id to the array tidsViewchangeend.push(tid); } // KML function clearKML() { if (ge !== null){ var features = ge.getFeatures(); while (features.getFirstChild()) { features.removeChild(features.getFirstChild()); } } } function showKML() { var kmlList = di.readVariable(DEFAULT_NAMESPACE, "KML_List"); if (kmlList !== null) { if (kmlList.length === 0){ //clearKML(); } for (var i=0, len=kmlList.length; i<len; i++) { parsed = ge.parseKml(kmlList[i]); if (parsed !== null){ // TODO: better test for ge if (ge !== null){ ge.getFeatures().appendChild(parsed); } } else{ debugLog('Problem parsing element ' + i + ' in KML_List'); } } } } function updatePlacemarkStyles(dsName) { var pubDataset = di.readVariable(DEFAULT_NAMESPACE, dsName).toJSON(); placemarks = _KMLPointList; debugger; for (var i=0, len=pubDataset.length; i<len; i++) { var rec = pubDataset[i]; if (rec.hasOwnProperty("db_CelestialCoord") && rec.hasOwnProperty("db_color")) { var cc = rec["db_CelestialCoord"]; var color = rec["db_color"]; var kmlItem = getKmlItemById(placemarks, cc.getId()); if (kmlItem === null) { // create the kml and append it createPlacemarkFromCC(cc); // TODO: make this cleaner // sets the cc id as the kmlid debugger; cc.setId(parsed.getId()); } else { // look up the (possibly new) color and set the style based on it if (iconUrlStyles.hasOwnProperty(color)) { kmlItem.setStyleSelector(iconUrlStyles[color].style); } else if (color === "" || color === "default") { kmlItem.setStyleSelector(iconUrlStyles["grey"].style); } } } } } function createPlacemarkFromCC(cc) { var geFeatures = ge.getFeatures(); parsed = ge.parseKml(cc.getKML()); geFeatures.appendChild(parsed); var kmlItem = new KMLListItem(); kmlItem.KMLObj = parsed; _KMLPointList.push(kmlItem); } function getKmlItemById(items, id) { for (var i=0, len=items.length; i<len; i++) {; // TODO: check ids for duplicates including "" ! var id = items[i].KMLObj.getId(); if (id !== "" && items[i].KMLObj.getId() === id) { return items[i].KMLObj; } } return null; } function plotAllFromDataset(dsName) { var pubDataset = di.readVariable(DEFAULT_NAMESPACE, dsName).toJSON(); var toPlotStrings = []; //clearKML(); for (var i=0, len=pubDataset.length; i<len; i++) { if (pubDataset[i].hasOwnProperty("db_CelestialCoord")) { toPlotStrings.push(pubDataset[i].db_CelestialCoord.getKML()); } } // PLOT the kml objects in toPlot if (ge !== null){ var geFeatures = ge.getFeatures(); // speed up the getFeatures methods for (var i=0,len=toPlotStrings.length; i<len; i++){ parsed = ge.parseKml(toPlotStrings[i]); geFeatures.appendChild(parsed); var kmlItem = new KMLListItem(); kmlItem.KMLObj = parsed; _KMLPointList.push(kmlItem); // THIS WORKS - It's possible to modify a KML object after it's been appended //parsed.setDescription("MODIFIED"); } } } function refreshKMLFromDataset(dsName, privList) { var pubDataset = di.readVariable(DEFAULT_NAMESPACE, dsName); var toPlot = []; var toRemove = []; } // END refreshKMLFromDataset function refreshKMLFromList(pubListName, privList) { // Sync the pub and priv lists var pubList = di.readVariable(DEFAULT_NAMESPACE, pubListName); var toPlot = []; // array of ids to plot var toRemove = []; // array of ids to remove // compare the ids from pubList to the ids in the privList // first find points to remove // TODO: Is there a faster way to search these arrays? // loop thru privList looking for points NOT in pubList // loop backwards so we can splice array in loop for (var i=privList.length-1; i>=0; i--) { if ((pubList.getItemById(privList[i].listItemId) === null) || (pubList.isIdModified(privList[i].listItemId))) { // has been removed from the pubList, so add it to the toRemove list // and remove it from the privList toRemove.push(privList[i].KMLobj); // add the KMLobj to the remove list privList.splice(i,1); // remove it from privList } } // TODO: check isPlotted! // next find the new points to plot // loop thru pub list looking for points NOT in priv list (they are new points) for (var i=0, len=pubList.getLength(); i<len; i++){ var pubItemId = pubList.getIdByIndex(i); var found = false; // check for this id in the priv list for (var i2=0, len2=privList.length; i2<len2; i2++){ if (privList[i2].listItemId === pubItemId) { found = true; //break; // break actually breaks out of both for's, so lets just reset i=len // TODO: CHANGE THIS BAD FORM i2 = len; } } if (!found){ // we found a NEW point in the pubList (not in privList) // add it to the toPlot array toPlot.push(pubItemId) } } // Find indexes of modified points var modifiedIdsList = pubList.getModifiedIds(); for (var i=0, len=modifiedIdsList.length; i<len; i++){ // toPlot.push(modifiedIdsList[i]); pubList.setModifiedById(modifiedIdsList[i]); } // alert('Modified IDs: ' + modifiedIdsList); // sync the GE to the priv list // TODO: better test for GE if (ge !== null){ var geFeatures = ge.getFeatures(); // speed up the getFeatures methods // REMOVE the kmlobjects in toRemove for (var i=0,len=toRemove.length; i<len; i++){ geFeatures.removeChild(toRemove[i]); } // PLOT the kml objects in toPlot for (var i=0,len=toPlot.length; i<len; i++){ // first we plot it var kmlText = pubList.getItemByIndex(toPlot[i]).getKML(); parsed = ge.parseKml(kmlText); geFeatures.appendChild(parsed); // then add it to the privList var privItem = new KMLListItem(); privItem.KMLobj = parsed; privItem.listItemId = toPlot[i]; privItem.isPlotted = true; privList.push(privItem); } } } // HELPER function clearTimerArray(timers){ if (timers instanceof Array){ for (var i=0, len=timers.length; i<len; i++){ clearTimeout(timers.splice(i,1)); // splice returns the removed element } } } function createIconStyles(styles) { for (var color in styles) { if (styles.hasOwnProperty(color)) { var icon = ge.createIcon(''); icon.setHref(styles[color].url); var style = ge.createStyle(''); style.getIconStyle().setIcon(icon); styles[color].kmlStyle = style; } } } return my; } gadgets.util.registerOnLoadHandler(init); </script> <div id="sky_map" style="height:500px; width:100%;"> <!-- <input type="button" value="clear KML" onclick="ks.clearKML()"> --> </div> ]]></Content> </Module>