Skip to content

Commit

Permalink
🚧 First iteration of the js refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
Xen0Xys committed Apr 23, 2024
1 parent ebdd6ac commit dd08e8a
Show file tree
Hide file tree
Showing 3 changed files with 304 additions and 229 deletions.
228 changes: 228 additions & 0 deletions js/models/event_handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
import MessageHandler from "./message_handler";

export default class EventHandler {
constructor(A, aladin, model) {
this.A = A;
this.aladin = aladin;
this.model = model;
this.messageHandler = new MessageHandler(A, aladin);
}

subscribeAll() {
/* ------------------- */
/* Listeners --------- */
/* ------------------- */

/* Position Control */
// there are two ways of changing the target, one from the javascript side, and
// one from the python side. We have to instantiate two listeners for these, but
// the gotoObject call should only happen once. The two booleans prevent the two
// listeners from triggering each other and creating a buggy loop. The same trick
// is also necessary for the field of view.

/* Target control */
let targetJs = false;
let targetPy = false;

// Event triggered when the user moves the map in Aladin Lite
this.aladin.on("positionChanged", () => {
if (targetPy) {
targetPy = false;
return;
}
targetJs = true;
const raDec = this.aladin.getRaDec();
this.model.set("_target", `${raDec[0]} ${raDec[1]}`);
this.model.set("shared_target", `${raDec[0]} ${raDec[1]}`);
this.model.save_changes();
});

// Event triggered when the target is changed from the Python side using jslink
this.model.on("change:shared_target", () => {
if (targetJs) {
targetJs = false;
return;
}
targetPy = true;
const target = this.model.get("shared_target");
const [ra, dec] = target.split(" ");
this.aladin.gotoRaDec(ra, dec);
});

/* Field of View control */
let fovJs = false;
let fovPy = false;

this.aladin.on("zoomChanged", (fov) => {
if (!fovPy) {
fovJs = true;
// fov MUST be cast into float in order to be sent to the model
this.model.set("fov", parseFloat(fov.toFixed(5)));
this.model.save_changes();
} else {
fovPy = false;
}
});

this.model.on("change:fov", () => {
if (!fovJs) {
fovPy = true;
let fov = this.model.get("fov");
this.aladin.setFoV(fov);
} else {
fovJs = false;
}
});

/* Div control */

this.model.on("change:height", () => {
let height = this.model.get("height");
aladinDiv.style.height = `${height}px`;
});

/* Aladin callbacks */

this.aladin.on("objectHovered", (object) => {
if (object["data"] !== undefined) {
this.model.send({
event_type: "object_hovered",
content: {
ra: object["ra"],
dec: object["dec"],
},
});
}
});

this.aladin.on("objectClicked", (clicked) => {
let clickedContent = {
ra: clicked["ra"],
dec: clicked["dec"],
};
if (clicked["data"] !== undefined) {
clickedContent["data"] = clicked["data"];
}
this.model.set("clicked", clickedContent);
// send a custom message in case the user wants to define their own callbacks
this.model.send({
event_type: "object_clicked",
content: clickedContent,
});
this.model.save_changes();
});

this.aladin.on("click", (clickContent) => {
this.model.send({
event_type: "click",
content: clickContent,
});
});

this.aladin.on("select", (catalogs) => {
let objectsData = [];
// TODO: this flattens the selection. Each object from different
// catalogs are entered in the array. To change this, maybe change
// upstream what is returned upon selection?
catalogs.forEach((catalog) => {
catalog.forEach((object) => {
objectsData.push({
ra: object.ra,
dec: object.dec,
data: object.data,
x: object.x,
y: object.y,
});
});
});
this.model.send({
event_type: "select",
content: objectsData,
});
});

/* Aladin functionalities */

this.model.on("change:coo_frame", () => {
this.aladin.setFrame(this.model.get("coo_frame"));
});

this.model.on("change:survey", () => {
this.aladin.setImageSurvey(this.model.get("survey"));
});

this.model.on("change:overlay_survey", () => {
this.aladin.setOverlayImageLayer(this.model.get("overlay_survey"));
});

this.model.on("change:overlay_survey_opacity", () => {
this.aladin
.getOverlayImageLayer()
.setAlpha(this.model.get("overlay_survey_opacity"));
});

this.model.on("msg:custom", (msg, buffers) => {
let options = {};
switch (msg["event_name"]) {
case "goto_ra_dec":
this.messageHandler.handleGotoRaDec(msg["ra"], msg["dec"]);
break;
case "add_catalog_from_URL":
this.messageHandler.handleAddCatalogFromURL(
msg["votable_URL"],
msg["options"],
);
break;
case "add_MOC_from_URL":
this.messageHandler.handleAddMOCFromURL(
msg["moc_URL"],
msg["options"],
);
break;
case "add_MOC_from_dict":
this.messageHandler.handleAddMOCFromDict(
msg["moc_dict"],
msg["options"],
);
break;
case "add_overlay_from_stcs":
this.messageHandler.handleAddOverlayFromSTCS(
msg["overlay_options"],
msg["stc_string"],
);
break;
case "change_colormap":
this.messageHandler.handleChangeColormap(msg["colormap"]);
break;
case "get_JPG_thumbnail":
this.messageHandler.handleGetJPGThumbnail();
break;
case "trigger_rectangular_selection":
this.messageHandler.handleTriggerRectangularSelection();
break;
case "add_table":
this.messageHandler.handleAddTable(buffers[0].buffer, msg.options);
break;
}
});
}

unsubscribeAll() {
this.model.off("change:shared_target");
this.model.off("change:fov");
this.model.off("change:height");
this.model.off("change:coo_frame");
this.model.off("change:survey");
this.model.off("change:overlay_survey");
this.model.off("change:overlay_survey_opacity");
this.model.off("change:trigger_event");
this.model.off("msg:custom");

this.aladin.off("positionChanged");
this.aladin.off("zoomChanged");
this.aladin.off("objectHovered");
this.aladin.off("objectClicked");
this.aladin.off("click");
this.aladin.off("select");
}
}
62 changes: 62 additions & 0 deletions js/models/message_handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
export default class MessageHandler {
constructor(A, aladin) {
this.A = A;
this.aladin = aladin;
}

handleGotoRaDec(ra, dec) {
this.aladin.gotoRaDec(ra, dec);
}

handleAddCatalogFromURL(votableURL, options) {
this.aladin.addCatalog(this.A.catalogFromURL(votableURL, options));
}

handleAddMOCFromURL(mocURL, options) {
if (options["lineWidth"] === undefined) {
options["lineWidth"] = 3;
}
this.aladin.addMOC(this.A.MOCFromURL(mocURL, options));
}

handleAddMOCFromDict(mocDict, options) {
if (options["lineWidth"] === undefined) {
options["lineWidth"] = 3;
}
this.aladin.addMOC(this.A.MOCFromJSON(mocDict, options));
}

handleAddOverlayFromSTCS(overlayOptions, stcString) {
let overlay = this.A.graphicOverlay(overlayOptions);
this.aladin.addOverlay(overlay);
overlay.addFootprints(this.A.footprintsFromSTCS(stcString));
}

handleChangeColormap(colormap) {
this.aladin.getBaseImageLayer().setColormap(colormap);
}

handleGetJPGThumbnail() {
this.aladin.exportAsPNG();
}

handleTriggerRectangularSelection() {
this.aladin.select();
}

handleAddTable(buffer, options) {
let tableBytes = buffer;
let decoder = new TextDecoder("utf-8");
let blob = new Blob([decoder.decode(tableBytes)]);
let url = URL.createObjectURL(blob);
this.A.catalogFromURL(
url,
Object.assign(options, { onClick: "showTable" }),
(catalog) => {
this.aladin.addCatalog(catalog);
},
false,
);
URL.revokeObjectURL(url);
}
}
Loading

0 comments on commit dd08e8a

Please sign in to comment.