Source: public/javascript/modules/olqv_boxes.js

  1. import {ShapesFactory} from "./olqv_shapes.js";
  2. import { box2DTranslator, box3DTranslator } from "./olqv_selector.js";
  3. import {DOMAccessor} from "./domelements.js";
  4. import { ServerApi } from "./serverApi.js";
  5. import {highlightedFeature, standardFeature} from "./olqv_shapestyle.js";
  6. import {BoxButton} from "./olqv_olbuttons.js";
  7. /** A class to create and to manage rectangular boxes in the 2D part of YAFITS. A box is basically defined by a pair of opposite corners.
  8. *
  9. * Boxes are created and manipulated with the {@link https://openlayers.org/en/v5.3.0/apidoc/|OpenLayers} API.
  10. * In particular the {@link https://openlayers.org/en/v5.3.0/apidoc/module-ol_interaction_DragBox.html|DragBox}
  11. * and {@link https://openlayers.org/en/v5.3.0/apidoc/module-ol_Feature-Feature.html|Feature} classes are used.
  12. *
  13. * Boxes style is defined in ShapesFactory
  14. *
  15. * <ul>
  16. * <li>Boxes have their side parallels to the image sides (No rotation possible).</li>
  17. * <li>A method is provided to obtain measurements associated to the collection of pixels contained in a box. </li>
  18. * </ul>
  19. *
  20. * @extends ShapesFactory
  21. */
  22. class BoxesFactory extends ShapesFactory {
  23. static enter(what) {
  24. console.group(this.name + "." + what);
  25. }
  26. static exit() {
  27. console.groupEnd();
  28. }
  29. /**
  30. * Creates an instance.
  31. * @param {Viewer} viewer instance of the Viewer class that will host the boxes.
  32. */
  33. constructor(viewer) {
  34. super(viewer, 'box');
  35. BoxesFactory.enter(this.constructor.name);
  36. this.mode = this;
  37. this.lastSelectedBox = null;
  38. this.layer.setZIndex(30);
  39. this.buttonObject = new BoxButton(this.viewer);
  40. let self = this;
  41. let f = function (event) {
  42. if(self.isOpened){
  43. self.close();
  44. self.buttonObject.unsetActive();
  45. } else {
  46. self.open(self.dragBox, 'nesw-resize');
  47. self.buttonObject.setActive();
  48. }
  49. };
  50. this.buttonObject.setClickAction(f);
  51. this.numOfBoxes = 0; // The number of boxes created sbsiao far
  52. /*
  53. ** This is our dragbox interaction
  54. */
  55. //this.dragBox = new ol.interaction.DragBox({ condition: ol.events.condition.platformModifierKeyOnly });
  56. this.dragBox = new ol.interaction.DragBox({ condition: ol.events.condition.noModifierKeys });
  57. this.dragBox.on('boxend', () => {
  58. ShapesFactory.enter("this.dragBox.on('boxend', function() { : entering");
  59. const extent = this.dragBox.getGeometry().getExtent();
  60. this.addBox(extent[0], extent[2], extent[1], extent[3]);
  61. /*
  62. // The real work when a drag box interaction reach its end is done below ( saynchronously )
  63. //this.createAndMeasureBox(this.relFITSFilePath, this.viewer.getSliceRange()[0], extent[0], extent[2], extent[1], extent[3]);
  64. let box = this.prepareBox(extent[0], extent[2], extent[1], extent[3]);
  65. this.measure(box);
  66. this.numOfBoxes += 1;*/
  67. ShapesFactory.exit();
  68. });
  69. /*
  70. ** This the behaviour when a box has been selected.
  71. */
  72. this.selector.select['Polygon'] = (feature) => {
  73. ShapesFactory.enter("A box is selected");
  74. this.selected(feature);
  75. ShapesFactory.exit();
  76. };
  77. /*
  78. ** This the behaviour when a box has been unselected.
  79. */
  80. this.selector.unselect['Polygon'] = (feature) => {
  81. ShapesFactory.enter("A box is unselected");
  82. this.unselected(feature);
  83. ShapesFactory.exit();
  84. };
  85. /*
  86. ** This is the behaviour when a selected box is going to be removed
  87. */
  88. this.selector.remove['Polygon'] = (f) => {
  89. ShapesFactory.enter("A selected box is about to be removed");
  90. this.remove(f);
  91. ShapesFactory.exit();
  92. };
  93. this._setBoxTranslator();
  94. this.selector.setTranslateInteraction(this);
  95. BoxesFactory.exit();
  96. }
  97. _setBoxTranslator(){
  98. Object.assign(this.selector, box2DTranslator);
  99. }
  100. addBox(iRA0, iRA1, iDEC0, iDEC1){
  101. // The real work when a drag box interaction reach its end is done below ( saynchronously )
  102. //this.createAndMeasureBox(this.relFITSFilePath, this.viewer.getSliceRange()[0], extent[0], extent[2], extent[1], extent[3]);
  103. DOMAccessor.showLoaderAction(true);
  104. let box = this.prepareBox(iRA0, iRA1, iDEC0, iDEC1);
  105. this.measure(box);
  106. this.numOfBoxes += 1;
  107. this.viewer.map.updateSize();
  108. DOMAccessor.showLoaderAction(false);
  109. }
  110. /**
  111. * Utility. Returns the toolbox button that will activate this instance.
  112. * @returns a {@link https://developer.mozilla.org/fr/docs/Web/HTML/Element/Button|button}
  113. */
  114. getButtonObject() {
  115. return this.buttonObject;
  116. }
  117. /**
  118. * Creates an OpenLayers feature that describres a box given bottom left and upper right coordinates.
  119. * A label is automatically generated that will be displayed beside the box.
  120. * @param {number} iRA0 lower 1st coordinate
  121. * @param {*} iRA1 upper 1st coordinate
  122. * @param {*} iDEC0 lower 2nd coordinate
  123. * @param {*} iDEC1 upper 2nd coordinate
  124. * @returns {Feature}
  125. */
  126. prepareBox(iRA0, iRA1, iDEC0, iDEC1) {
  127. ShapesFactory.enter(this.prepareBox.name);
  128. //DOMAccessor.getLoading().style.display = 'block';
  129. var tl = [iRA0, iDEC1];
  130. var tr = [iRA1, iDEC1];
  131. var br = [iRA1, iDEC0];
  132. var bl = [iRA0, iDEC0];
  133. var corners = [];
  134. corners.push(tl, tr, br, bl, tl);
  135. let feature = new ol.Feature({ geometry: new ol.geom.Polygon([corners]) });
  136. let properties = {};
  137. properties["type"] = "box";
  138. feature.set("properties", properties);
  139. feature.set("label", `b_${this.numOfBoxes}`);
  140. feature.setStyle(standardFeature(feature));
  141. ShapesFactory.exit();
  142. return feature;
  143. }
  144. /**
  145. * Calculates some measurements associated to the box described in feature.
  146. * The measurements are stored in an entry "measurements" of feature "properties" property.
  147. *
  148. * > The measurements are calculated remotely by the YAFITSS server.
  149. *
  150. * @param {Feature} feature the OpenLayers feature expected to represent a box.
  151. * @param {boolean} addFeature Deprecated, don't use it.
  152. */
  153. measure(feature, addFeature = true) {
  154. BoxesFactory.enter(this.measure.name);
  155. console.warn("range : " + this.viewer.getSliceRange());
  156. if (typeof this.viewer.getSliceRange() != "number") {
  157. alert("Do not know how to measure a 2D box on an image representing a 3D dataset");
  158. }
  159. else {
  160. let properties = feature.get("properties");
  161. if (properties.hasOwnProperty("type") && properties["type"] === "box") {
  162. //DOMAccessor.getLoading().style.display = "block";
  163. DOMAccessor.showLoaderAction(true);
  164. let corners = feature.getGeometry().getCoordinates()[0];
  165. let iRA0, iRA1, iDEC0, iDEC1;
  166. [iRA0, iRA1] = [Math.min(corners[0][0], corners[2][0]), Math.max(corners[0][0], corners[2][0])];
  167. [iDEC0, iDEC1] = [Math.min(corners[0][1], corners[2][1]), Math.max(corners[0][1], corners[2][1])];
  168. // query server
  169. let serverApi = new ServerApi();
  170. serverApi.measureBox(iRA0, iRA1, iDEC0, iDEC1, this.viewer.getSliceRange(), this.relFITSFilePath, (resp)=>{
  171. properties["measurements"] = resp["result"];
  172. feature.set("properties", properties);
  173. if (addFeature) {
  174. feature.setStyle(this.style_f(feature));
  175. this.source.addFeature(feature);
  176. this.viewer.map.updateSize();
  177. }
  178. });
  179. }
  180. else {
  181. console.log("Unable to measure such a feature");
  182. }
  183. }
  184. BoxesFactory.exit();
  185. }
  186. /**
  187. * Behaviour when an instance is activated.
  188. *
  189. * @see {@link https://openlayers.org/en/v5.3.0/apidoc/module-ol_interaction_Interaction-Interaction.html|Interaction }
  190. * @see {@link https://developer.mozilla.org/fr/docs/Web/CSS/cursor | cursor}
  191. * @param {Interaction} interaction
  192. * @param {cursor} cursor
  193. */
  194. open(interaction, cursor) {
  195. BoxesFactory.enter(this.open.name);
  196. super.open(interaction, cursor);
  197. BoxesFactory.exit();
  198. }
  199. /**
  200. * Behaviour when a box is selected.
  201. * @param {Feature} box
  202. */
  203. selected(box) {
  204. ShapesFactory.enter(this.selected.name);
  205. super.selected(box);
  206. ShapesFactory.exit();
  207. }
  208. }
  209. class Boxes3DFactory extends BoxesFactory {
  210. /**
  211. * Creates an instance.
  212. * @param {Viewer} viewer instance of the Viewer class that will host the boxes.
  213. */
  214. constructor(viewer) {
  215. super(viewer);
  216. this.selectAction = undefined;
  217. }
  218. _setBoxTranslator(){
  219. Object.assign(this.selector, box3DTranslator);
  220. }
  221. addBox(iRA0, iRA1, iDEC0, iDEC1){
  222. // The real work when a drag box interaction reach its end is done below ( saynchronously )
  223. //this.createAndMeasureBox(this.relFITSFilePath, this.viewer.getSliceRange()[0], extent[0], extent[2], extent[1], extent[3]);
  224. DOMAccessor.showLoaderAction(true);
  225. let boxFeature = this.prepareBox(iRA0, iRA1, iDEC0, iDEC1);
  226. boxFeature.setStyle(this.style_f(boxFeature));
  227. this.source.addFeature(boxFeature);
  228. this.numOfBoxes += 1;
  229. //make sure the box is immediately visible
  230. this.viewer.map.updateSize();
  231. DOMAccessor.showLoaderAction(false);
  232. }
  233. setSelectAction(action){
  234. this.selectAction = action;
  235. }
  236. /**
  237. * Behaviour when a box is selected.
  238. * @param {Feature} box
  239. */
  240. selected(box) {
  241. ShapesFactory.enter(this.selected.name);
  242. super.selected(box);
  243. if (this.selectAction !== undefined){
  244. this.selectAction(box);
  245. }
  246. ShapesFactory.exit();
  247. }
  248. }
  249. export {
  250. BoxesFactory,
  251. Boxes3DFactory
  252. }