From 3d85f48d767c0986a01dc451f382391c29de9c29 Mon Sep 17 00:00:00 2001 From: Jeffrey SubbaRao Date: Mon, 20 May 2019 15:54:01 -0500 Subject: [PATCH] First version of the html and js files needed for the interactive figure. More states need to be serialized/decoded and the user notification of errors could be improved. --- .../static/interactive_figure/index.html | 29 +++ .../interactive_figure/interactive_figure.js | 236 ++++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100644 pywwt/nbextension/static/interactive_figure/index.html create mode 100644 pywwt/nbextension/static/interactive_figure/interactive_figure.js diff --git a/pywwt/nbextension/static/interactive_figure/index.html b/pywwt/nbextension/static/interactive_figure/index.html new file mode 100644 index 0000000..f2fd3f9 --- /dev/null +++ b/pywwt/nbextension/static/interactive_figure/index.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + +
+
+ + diff --git a/pywwt/nbextension/static/interactive_figure/interactive_figure.js b/pywwt/nbextension/static/interactive_figure/interactive_figure.js new file mode 100644 index 0000000..2ba8c3a --- /dev/null +++ b/pywwt/nbextension/static/interactive_figure/interactive_figure.js @@ -0,0 +1,236 @@ +var wwtIntialState; + +var wwt; +var wwt_ready = 0; + +function initialize() { + // The true enables WebGL + wwt = wwtlib.WWTControl.initControlParam("WWTCanvas", true); + wwt.add_ready(loadWwtFigure); + wwt.add_ready(keyScroll); +} + +$.getJSON('wwt_figure.json') + .done(function (data) { wwtIntialState = data; }) + .error(function (err) { + wwtIntialState = null; + handleConfigLoadError(); + }); + +function keyScroll() { + + i = 0; + var canvas = document.body.getElementsByTagName("canvas")[0]; + + function newEvent(action, attributes, deprecated) { + if (!deprecated) + var event = new CustomEvent(action); + else { + var event = document.createEvent("CustomEvent"); + event.initEvent(action, false, false); + } + if (attributes) + for (var attr in attributes) + event[attr] = attributes[attr]; + + return event; + } + + + var wheelUp = newEvent("wwt-zoom", { deltaY: 53, delta: 53 }, true); + var wheelDn = newEvent("wwt-zoom", { deltaY: -53, delta: -53 }, true); + + var mouseLf = newEvent("wwt-move", { movementX: 53, movementY: 0 }, true); + var mouseUp = newEvent("wwt-move", { movementX: 0, movementY: 53 }, true); + var mouseRg = newEvent("wwt-move", { movementX: -53, movementY: 0 }, true); + var mouseDn = newEvent("wwt-move", { movementX: 0, movementY: -53 }, true); + + zoomCodes = { + "KeyZ": wheelUp, "KeyX": wheelDn, + 90: wheelUp, 88: wheelDn + }; + moveCodes = { + "KeyJ": mouseLf, "KeyI": mouseUp, + "KeyL": mouseRg, "KeyK": mouseDn, + 74: mouseLf, 73: mouseUp, 76: mouseRg, 75: mouseDn + }; + + window.addEventListener("keydown", function (event) { + if (zoomCodes.hasOwnProperty(event.code) || + zoomCodes.hasOwnProperty(event.keyCode)) { + var action = zoomCodes.hasOwnProperty(event.code) ? + zoomCodes[event.code] : zoomCodes[event.keyCode]; + if (event.shiftKey) { action.shiftKey = 1; } + else { action.shiftKey = 0; } + canvas.dispatchEvent(action); + } + + if (moveCodes.hasOwnProperty(event.code) || + moveCodes.hasOwnProperty(event.keyCode)) { + var action = moveCodes.hasOwnProperty(event.code) ? + moveCodes[event.code] : moveCodes[event.keyCode]; + if (event.shiftKey) { action.shiftKey = 1; } + else { action.shiftKey = 0; } + if (event.altKey) { action.altKey = 1; } + else { action.altKey = 0; } + canvas.dispatchEvent(action); + } + }); + + canvas.addEventListener("wwt-move", (function (proceed) { + return function (event) { + if (!proceed) { return false; } + proceed = false; + + if (event.shiftKey) { delay = 500; } + else { delay = 100; } + setTimeout(function () { proceed = true }, delay); + if (event.altKey) + wwtlib.WWTControl.singleton._tilt(event.movementX, event.movementY); + else + wwtlib.WWTControl.singleton.move(event.movementX, event.movementY); + } + })(true)); + + canvas.addEventListener("wwt-zoom", (function (proceed) { + return function (event) { + if (!proceed) { return false; } + proceed = false; + + if (event.shiftKey) { delay = 500; } // milliseconds + else { delay = 100; } + setTimeout(function () { proceed = true }, delay); + + if (event.deltaY < 0) { wwtlib.WWTControl.singleton.zoom(1.43); } + else { wwtlib.WWTControl.singleton.zoom(0.7); } + } + })(true)); +} + +function loadWwtFigure() { + if (wwtIntialState === undefined) { //JSON config file has not loaded yet, try again in 50 ms + setTimeout(loadWwtFigure, 50); + return; + } + else if (wwtIntialState === null) { //There was an error loading the config + return; + } + //TODO allow loading more collections + wwt.loadImageCollection('https://WorldWideTelescope.github.io/pywwt/surveys.xml') + + var viewSettings = wwtIntialState['view_settings']; + wwt_apply_json_message(wwt, { + event: 'set_viewer_mode', + mode: viewSettings['mode'] + }); + wwt.gotoRaDecZoom(viewSettings['ra'], viewSettings['dec'], viewSettings['fov'], true); + + if (viewSettings['mode'] == 'sky') { + var foregroundState = wwtIntialState['foreground_settings']; + wwt.setForegroundImageByName(foregroundState['foreground']); + wwt.setBackgroundImageByName(foregroundState['background']); + wwt.setForegroundOpacity(foregroundState['foreground_alpha']); + } + + var miscSettings = wwtIntialState['wwt_settings']; + wwtIntialState['wwt_settings'].forEach(function (setting) { + wwt_apply_json_message(wwt, { + event: 'setting_set', + setting: setting['name'], + value: setting['value'] + }); + }); + + wwtIntialState['layers'].forEach(function (layerInfo) { + if (layerInfo['layer_type'] == 'image') { + loadImageLayer(layerInfo); + } + else if (layerInfo['layer_type'] == 'table') { + loadTableLayer(layerInfo); + } + }); +} + + +function loadImageLayer(layerInfo) { + var id = layerInfo['id']; + var url = 'data/' + id + '.fits'; + var onFitsLoad = function (layer) { + var stertchInfo = layerInfo['stretch_info']; + wwtLayer.setImageScale(stertchInfo['stretch'], + stertchInfo['vmin'], + stertchInfo['vmax']); + layer.getFitsImage().transparentBlack = false; + + layerInfo['settings'].forEach(function (setting) { + wwt_apply_json_message(wwt, { + event: 'image_layer_set', + setting: setting['name'], + value: setting['value'], + id: id + }); + }); + }; + + var wwtLayer = wwt.loadFitsLayer(url, '', false, onFitsLoad); + wwt.layers[id] = wwtLayer; +} + +function loadTableLayer(layerInfo) { + var id = layerInfo['id']; + var url = 'data/' + id + '.csv'; + var onCsvLoad = function (data) { + wwt_apply_json_message(wwt, { + event: 'table_layer_create', + frame: layerInfo['frame'], + id: id, + table: btoa(data) + }); + + layerInfo['settings'].forEach(function (setting) { + if (setting['value'] !== null) { + wwt_apply_json_message(wwt, { + event: 'table_layer_set', + setting: setting['name'], + value: setting['value'], + id: id + }); + } + }); + }; + + $.ajax(url, datatype = "text") + .fail(function () { + $("#WWTErrorText").append("

Unable to load data for layer with ID: " + id + "

"); //TODO replace with something nicer + }) + .done(onCsvLoad); +} + +function setHmtlSettings() { + if (wwtIntialState === undefined) { //JSON config file has not loaded yet, try again in 50 ms + setTimeout(setHmtlSettings, 50); + return; + } + else if (wwtIntialState === null) { + return; + } + var figHtmlSettings = wwtIntialState['html_settings']; + + var title = figHtmlSettings['title'] ? figHtmlSettings['title'] : "WWT Interactive Figure"; + $(document).attr("title", title); + + var settingsHeight = figHtmlSettings['height']; + var settingsWidth = figHtmlSettings['width']; + var htmlHeight = $("html").height(); + var htmlWidth = $("html").width(); + var newHeight = settingsHeight ? Math.min(settingsHeight, htmlHeight) : htmlHeight; + var newWidth = settingsWidth ? Math.min(settingsWidth, htmlWidth) : htmlWidth; + $("#WWTCanvas").css("height", newHeight + "px"); + $("#WWTCanvas").css("width", newWidth + "px"); +} + +function handleConfigLoadError() { + //TODO replace with something a bit nicer before releasing this feature + $("#WWTCanvas").hide; + $("#WWTErrorText").append("

Unable to load configuration file wwt_figure.json

"); +} \ No newline at end of file