AtImageView.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. const { I } = inject();
  2. const assert = require("assert");
  3. const Helpers = require("../tests/helpers");
  4. module.exports = {
  5. _stageSelector: ".konvajs-content",
  6. _stageFrameSelector: '[class^="frame--"]',
  7. _stageBBox: null,
  8. _toolBarSelector: ".lsf-toolbar",
  9. _zoomPresetsSelector: '[title^="Zoom presets"]',
  10. _rootSelector: '[class^="lsf-object wrapperComponent--"]',
  11. _paginationSelector: '[class^="pagination--"]',
  12. _paginationPrevBtnSelector: ".lsf-pagination__btn_arrow-left:not(.lsf-pagination__btn_arrow-left-double)",
  13. _paginationNextBtnSelector: ".lsf-pagination__btn_arrow-right:not(.lsf-pagination__btn_arrow-right-double)",
  14. locateRoot() {
  15. return locate(this._rootSelector);
  16. },
  17. locate(locator) {
  18. const rootLocator = this.locateRoot();
  19. return locator ? rootLocator.find(locator) : rootLocator;
  20. },
  21. locatePagination(locator) {
  22. const paginationLocator = this.locate(this._paginationSelector);
  23. return locator ? paginationLocator.find(locator) : paginationLocator;
  24. },
  25. locateToolByCode(toolCode) {
  26. return locate(`[aria-label=${toolCode}-tool]`);
  27. },
  28. percToX(xPerc) {
  29. return (this._stageBBox.width * xPerc) / 100;
  30. },
  31. percToY(yPerc) {
  32. return (this._stageBBox.height * yPerc) / 100;
  33. },
  34. async grabStageBBox() {
  35. const bbox = await I.grabElementBoundingRect(this._stageFrameSelector);
  36. return bbox;
  37. },
  38. async lookForStage() {
  39. await I.scrollPageToTop();
  40. this._stageBBox = await this.grabStageBBox();
  41. },
  42. stageBBox() {
  43. if (!this._stageBBox) console.log("Stage bbox wasn't grabbed");
  44. return (
  45. this._stageBBox ?? {
  46. x: 0,
  47. y: 0,
  48. width: 0,
  49. height: 0,
  50. }
  51. );
  52. },
  53. stageX() {
  54. if (!this._stageBBox) console.log("Stage bbox wasn't grabbed");
  55. return this._stageBBox?.x ?? 0;
  56. },
  57. stageY() {
  58. if (!this._stageBBox) console.log("Stage bbox wasn't grabbed");
  59. return this._stageBBox?.y ?? 0;
  60. },
  61. async waitForImage() {
  62. I.say("Waiting for image to be loaded");
  63. await I.executeScript(Helpers.waitForImage);
  64. I.waitForVisible("canvas", 5);
  65. },
  66. async getNaturalSize() {
  67. const sizes = await I.executeScript(Helpers.getNaturalSize);
  68. return sizes;
  69. },
  70. async getCanvasSize() {
  71. const sizes = await I.executeScript(Helpers.getCanvasSize);
  72. return sizes;
  73. },
  74. async getImageSize() {
  75. const sizes = await I.executeScript(Helpers.getImageSize);
  76. return sizes;
  77. },
  78. async getImageFrameSize() {
  79. const sizes = await I.executeScript(Helpers.getImageFrameSize);
  80. return sizes;
  81. },
  82. setZoom(scale, x, y) {
  83. I.executeScript(Helpers.setZoom, [scale, x, y]);
  84. I.waitTicks(3);
  85. },
  86. async getZoomProps() {
  87. return await I.executeScript(Helpers.getZoomProps);
  88. },
  89. /**
  90. * Click once on the main Stage
  91. * @param {number} x
  92. * @param {number} y
  93. */
  94. clickKonva(x, y) {
  95. I.executeScript(Helpers.clickKonva, [x, y]);
  96. },
  97. /**
  98. * Click multiple times on the main Stage
  99. * @param {number[][]} points
  100. */
  101. clickPointsKonva(points) {
  102. I.executeScript(Helpers.clickMultipleKonva, points);
  103. },
  104. /**
  105. * Click multiple times on the main Stage then close Polygon
  106. * @param {number[][]} points
  107. * @deprecated Use drawByClickingPoints instead
  108. */
  109. clickPolygonPointsKonva(points) {
  110. I.executeScript(Helpers.polygonKonva, points);
  111. },
  112. /**
  113. * Dragging between two points
  114. * @param {number} x
  115. * @param {number} y
  116. * @param {number} shiftX
  117. * @param {number} shiftY
  118. * @deprecated Use drawByDrag instead
  119. */
  120. dragKonva(x, y, shiftX, shiftY) {
  121. I.executeScript(Helpers.dragKonva, [x, y, shiftX, shiftY]);
  122. },
  123. /**
  124. * Get pixel color at point
  125. * @param {number} x
  126. * @param {number} y
  127. * @param {number[]} rgbArray
  128. * @param {number} tolerance
  129. */
  130. async hasPixelColor(x, y, rgbArray, tolerance = 3) {
  131. const colorPixels = await I.executeScript(Helpers.getKonvaPixelColorFromPoint, [x, y]);
  132. const hasPixel = Helpers.areEqualRGB(rgbArray, colorPixels, tolerance);
  133. return hasPixel;
  134. },
  135. // Only for debugging
  136. async whereIsPixel(rgbArray, tolerance = 3) {
  137. const points = await I.executeScript(Helpers.whereIsPixel, [rgbArray, tolerance]);
  138. return points;
  139. },
  140. async countKonvaShapes() {
  141. const count = await I.executeScript(Helpers.countKonvaShapes);
  142. return count;
  143. },
  144. async isTransformerExist() {
  145. const isTransformerExist = await I.executeScript(Helpers.isTransformerExist);
  146. return isTransformerExist;
  147. },
  148. async isRotaterExist() {
  149. const isRotaterExist = await I.executeScript(Helpers.isRotaterExist);
  150. return isRotaterExist;
  151. },
  152. /**
  153. * Returns the bounding box of the first found shape
  154. * The coordinates are relative to the window
  155. * @returns {Promise<{x: number, y: number, width: number, height: number}>}
  156. */
  157. async getRegionAbsoultePosition(regionId, includeStage = true) {
  158. const [shapeId, coords] = await I.executeScript((regionId) => {
  159. const annotation = Htx.annotationStore.selected;
  160. const region = annotation.regions.find((r) => r.cleanId === regionId);
  161. console.log(region);
  162. return [region.shapeRef._id, region.bboxCoordsCanvas];
  163. }, regionId);
  164. const position = coords
  165. ? {
  166. x: coords.left + (coords.right - coords.left) / 2,
  167. y: coords.top + (coords.bottom - coords.top) / 2,
  168. width: coords.right - coords.left,
  169. height: coords.bottom - coords.top,
  170. }
  171. : await I.executeScript(Helpers.getRegionAbsoultePosition, shapeId);
  172. return includeStage
  173. ? {
  174. ...position,
  175. x: position.x + this.stageX(),
  176. y: position.y + this.stageY(),
  177. }
  178. : position;
  179. },
  180. /**
  181. * Mousedown - mousemove - mouseup drawing on the ImageView. Works in couple of lookForStage.
  182. * @example
  183. * await AtImageView.lookForStage();
  184. * AtImageView.drawByDrag(50, 30, 200, 200);
  185. * @param x
  186. * @param y
  187. * @param shiftX
  188. * @param shiftY
  189. */
  190. drawByDrag(x, y, shiftX, shiftY) {
  191. I.scrollPageToTop();
  192. I.moveMouse(this.stageBBox().x + x, this.stageBBox().y + y);
  193. I.pressMouseDown();
  194. I.waitTicks(1);
  195. I.moveMouse(this.stageBBox().x + x + shiftX, this.stageBBox().y + y + shiftY, 3);
  196. I.waitTicks(1);
  197. I.pressMouseUp();
  198. I.waitTicks(1);
  199. },
  200. /**
  201. * Click through the list of points on the ImageView. Works in couple of lookForStage.
  202. * @example
  203. * await AtImageView.loolookkForStage();
  204. * AtImageView.drawByClickingPoints([[50,50],[100,50],[100,100],[50,100],[50,50]]);
  205. * @param {number[][]} points
  206. */
  207. drawByClickingPoints(points) {
  208. const lastPoint = points[points.length - 1];
  209. const prevPoints = points.slice(0, points.length - 1);
  210. I.scrollPageToTop();
  211. if (prevPoints.length) {
  212. for (const point of prevPoints) {
  213. I.clickAt(this.stageBBox().x + point[0], this.stageBBox().y + point[1]);
  214. }
  215. I.waitTicks(3); // wait before last click to fix polygons creation
  216. }
  217. I.clickAt(this.stageBBox().x + lastPoint[0], this.stageBBox().y + lastPoint[1]);
  218. },
  219. /**
  220. * Mousedown - mousemove - mouseup drawing through the list of points on the ImageView. Works in couple of lookForStage.
  221. * @example
  222. * await AtImageView.lookForStage();
  223. * AtImageView.drawThroughPoints([[50,50],[200,100],[50,200],[300,300]]);
  224. * @param {number[][]} points - list of pairs of coords
  225. * @param {"steps"|"rate"} mode - mode of firing mousemove event
  226. * @param {number} parameter - parameter for mode
  227. */
  228. drawThroughPoints(points, mode = "steps", parameter = 1) {
  229. I.scrollPageToTop();
  230. const calcSteps = {
  231. steps: () => parameter,
  232. rate: (p1, p2) => Math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2) / parameter,
  233. }[mode];
  234. const startPoint = points[0];
  235. I.moveMouse(this.stageBBox().x + startPoint[0], this.stageBBox().y + startPoint[1]);
  236. I.pressMouseDown();
  237. for (let i = 1; i < points.length; i++) {
  238. const prevPoint = points[i - 1];
  239. const curPoint = points[i];
  240. I.moveMouse(this.stageBBox().x + curPoint[0], this.stageBBox().y + curPoint[1], calcSteps(prevPoint, curPoint));
  241. }
  242. I.pressMouseUp();
  243. },
  244. clickAt(x, y) {
  245. I.scrollPageToTop();
  246. I.clickAt(this.stageBBox().x + x, this.stageBBox().y + y);
  247. I.waitTicks(3); // We gotta wait here because clicks on the canvas are not processed immediately
  248. },
  249. dblClickAt(x, y) {
  250. I.scrollPageToTop();
  251. I.dblClickAt(this.stageBBox().x + x, this.stageBBox().y + y);
  252. },
  253. drawByClick(x, y) {
  254. I.scrollPageToTop();
  255. this.clickAt(x, y);
  256. },
  257. async clickOnRegion(regionIndex) {
  258. const regionId = await I.executeScript((regionIndex) => {
  259. const regions = Htx.annotationStore.selected.regions;
  260. return regions[regionIndex]?.cleanId ?? undefined;
  261. }, regionIndex);
  262. assert.notEqual(regionId, undefined, "Region not found");
  263. const position = await this.getRegionAbsoultePosition(regionId, false);
  264. I.say("Clicking on a region at", `${position.x} ${position.y}`);
  265. this.clickAt(position.x, position.y);
  266. },
  267. async dragRegion(regions, findIndex, shiftX = 50, shiftY = 50) {
  268. const region = regions.find(findIndex);
  269. assert.notEqual(region, undefined, "Region not found");
  270. const position = await this.getRegionAbsoultePosition(region.id);
  271. I.say(`Drag region by ${shiftX} ${shiftY}`);
  272. await I.dragAndDropMouse(position, {
  273. x: position.x + shiftX,
  274. y: position.y + shiftY,
  275. });
  276. },
  277. selectPanTool() {
  278. I.say("Select pan tool");
  279. I.pressKey("H");
  280. },
  281. selectMoveTool() {
  282. I.say("Select move tool");
  283. I.pressKey("V");
  284. },
  285. selectToolByCode(toolCode) {
  286. I.click(this.locateToolByCode(toolCode));
  287. },
  288. hasSelectedTool(toolCode) {
  289. I.seeElement(`.lsf-tool_active${this.locateToolByCode(toolCode).toString()}`);
  290. },
  291. async multiImageGoForwardWithHotkey() {
  292. I.say("Attempting to go to the next image");
  293. I.pressKey("Ctrl+d");
  294. await this.waitForImage();
  295. },
  296. async multiImageGoBackwardWithHotkey() {
  297. I.say("Attempting to go to the next image");
  298. I.pressKey("Ctrl+a");
  299. await this.waitForImage();
  300. },
  301. async multiImageGoForward() {
  302. I.click(this.locatePagination(this._paginationNextBtnSelector));
  303. await this.waitForImage();
  304. },
  305. async multiImageGoBackward() {
  306. I.click(this.locatePagination(this._paginationPrevBtnSelector));
  307. await this.waitForImage();
  308. },
  309. };