const { I } = inject(); const assert = require("assert"); const Helpers = require("../tests/helpers"); module.exports = { _stageSelector: ".konvajs-content", _stageFrameSelector: '[class^="frame--"]', _stageBBox: null, _toolBarSelector: ".lsf-toolbar", _zoomPresetsSelector: '[title^="Zoom presets"]', _rootSelector: '[class^="lsf-object wrapperComponent--"]', _paginationSelector: '[class^="pagination--"]', _paginationPrevBtnSelector: ".lsf-pagination__btn_arrow-left:not(.lsf-pagination__btn_arrow-left-double)", _paginationNextBtnSelector: ".lsf-pagination__btn_arrow-right:not(.lsf-pagination__btn_arrow-right-double)", locateRoot() { return locate(this._rootSelector); }, locate(locator) { const rootLocator = this.locateRoot(); return locator ? rootLocator.find(locator) : rootLocator; }, locatePagination(locator) { const paginationLocator = this.locate(this._paginationSelector); return locator ? paginationLocator.find(locator) : paginationLocator; }, locateToolByCode(toolCode) { return locate(`[aria-label=${toolCode}-tool]`); }, percToX(xPerc) { return (this._stageBBox.width * xPerc) / 100; }, percToY(yPerc) { return (this._stageBBox.height * yPerc) / 100; }, async grabStageBBox() { const bbox = await I.grabElementBoundingRect(this._stageFrameSelector); return bbox; }, async lookForStage() { await I.scrollPageToTop(); this._stageBBox = await this.grabStageBBox(); }, stageBBox() { if (!this._stageBBox) console.log("Stage bbox wasn't grabbed"); return ( this._stageBBox ?? { x: 0, y: 0, width: 0, height: 0, } ); }, stageX() { if (!this._stageBBox) console.log("Stage bbox wasn't grabbed"); return this._stageBBox?.x ?? 0; }, stageY() { if (!this._stageBBox) console.log("Stage bbox wasn't grabbed"); return this._stageBBox?.y ?? 0; }, async waitForImage() { I.say("Waiting for image to be loaded"); await I.executeScript(Helpers.waitForImage); I.waitForVisible("canvas", 5); }, async getNaturalSize() { const sizes = await I.executeScript(Helpers.getNaturalSize); return sizes; }, async getCanvasSize() { const sizes = await I.executeScript(Helpers.getCanvasSize); return sizes; }, async getImageSize() { const sizes = await I.executeScript(Helpers.getImageSize); return sizes; }, async getImageFrameSize() { const sizes = await I.executeScript(Helpers.getImageFrameSize); return sizes; }, setZoom(scale, x, y) { I.executeScript(Helpers.setZoom, [scale, x, y]); I.waitTicks(3); }, async getZoomProps() { return await I.executeScript(Helpers.getZoomProps); }, /** * Click once on the main Stage * @param {number} x * @param {number} y */ clickKonva(x, y) { I.executeScript(Helpers.clickKonva, [x, y]); }, /** * Click multiple times on the main Stage * @param {number[][]} points */ clickPointsKonva(points) { I.executeScript(Helpers.clickMultipleKonva, points); }, /** * Click multiple times on the main Stage then close Polygon * @param {number[][]} points * @deprecated Use drawByClickingPoints instead */ clickPolygonPointsKonva(points) { I.executeScript(Helpers.polygonKonva, points); }, /** * Dragging between two points * @param {number} x * @param {number} y * @param {number} shiftX * @param {number} shiftY * @deprecated Use drawByDrag instead */ dragKonva(x, y, shiftX, shiftY) { I.executeScript(Helpers.dragKonva, [x, y, shiftX, shiftY]); }, /** * Get pixel color at point * @param {number} x * @param {number} y * @param {number[]} rgbArray * @param {number} tolerance */ async hasPixelColor(x, y, rgbArray, tolerance = 3) { const colorPixels = await I.executeScript(Helpers.getKonvaPixelColorFromPoint, [x, y]); const hasPixel = Helpers.areEqualRGB(rgbArray, colorPixels, tolerance); return hasPixel; }, // Only for debugging async whereIsPixel(rgbArray, tolerance = 3) { const points = await I.executeScript(Helpers.whereIsPixel, [rgbArray, tolerance]); return points; }, async countKonvaShapes() { const count = await I.executeScript(Helpers.countKonvaShapes); return count; }, async isTransformerExist() { const isTransformerExist = await I.executeScript(Helpers.isTransformerExist); return isTransformerExist; }, async isRotaterExist() { const isRotaterExist = await I.executeScript(Helpers.isRotaterExist); return isRotaterExist; }, /** * Returns the bounding box of the first found shape * The coordinates are relative to the window * @returns {Promise<{x: number, y: number, width: number, height: number}>} */ async getRegionAbsoultePosition(regionId, includeStage = true) { const [shapeId, coords] = await I.executeScript((regionId) => { const annotation = Htx.annotationStore.selected; const region = annotation.regions.find((r) => r.cleanId === regionId); console.log(region); return [region.shapeRef._id, region.bboxCoordsCanvas]; }, regionId); const position = coords ? { x: coords.left + (coords.right - coords.left) / 2, y: coords.top + (coords.bottom - coords.top) / 2, width: coords.right - coords.left, height: coords.bottom - coords.top, } : await I.executeScript(Helpers.getRegionAbsoultePosition, shapeId); return includeStage ? { ...position, x: position.x + this.stageX(), y: position.y + this.stageY(), } : position; }, /** * Mousedown - mousemove - mouseup drawing on the ImageView. Works in couple of lookForStage. * @example * await AtImageView.lookForStage(); * AtImageView.drawByDrag(50, 30, 200, 200); * @param x * @param y * @param shiftX * @param shiftY */ drawByDrag(x, y, shiftX, shiftY) { I.scrollPageToTop(); I.moveMouse(this.stageBBox().x + x, this.stageBBox().y + y); I.pressMouseDown(); I.waitTicks(1); I.moveMouse(this.stageBBox().x + x + shiftX, this.stageBBox().y + y + shiftY, 3); I.waitTicks(1); I.pressMouseUp(); I.waitTicks(1); }, /** * Click through the list of points on the ImageView. Works in couple of lookForStage. * @example * await AtImageView.loolookkForStage(); * AtImageView.drawByClickingPoints([[50,50],[100,50],[100,100],[50,100],[50,50]]); * @param {number[][]} points */ drawByClickingPoints(points) { const lastPoint = points[points.length - 1]; const prevPoints = points.slice(0, points.length - 1); I.scrollPageToTop(); if (prevPoints.length) { for (const point of prevPoints) { I.clickAt(this.stageBBox().x + point[0], this.stageBBox().y + point[1]); } I.waitTicks(3); // wait before last click to fix polygons creation } I.clickAt(this.stageBBox().x + lastPoint[0], this.stageBBox().y + lastPoint[1]); }, /** * Mousedown - mousemove - mouseup drawing through the list of points on the ImageView. Works in couple of lookForStage. * @example * await AtImageView.lookForStage(); * AtImageView.drawThroughPoints([[50,50],[200,100],[50,200],[300,300]]); * @param {number[][]} points - list of pairs of coords * @param {"steps"|"rate"} mode - mode of firing mousemove event * @param {number} parameter - parameter for mode */ drawThroughPoints(points, mode = "steps", parameter = 1) { I.scrollPageToTop(); const calcSteps = { steps: () => parameter, rate: (p1, p2) => Math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2) / parameter, }[mode]; const startPoint = points[0]; I.moveMouse(this.stageBBox().x + startPoint[0], this.stageBBox().y + startPoint[1]); I.pressMouseDown(); for (let i = 1; i < points.length; i++) { const prevPoint = points[i - 1]; const curPoint = points[i]; I.moveMouse(this.stageBBox().x + curPoint[0], this.stageBBox().y + curPoint[1], calcSteps(prevPoint, curPoint)); } I.pressMouseUp(); }, clickAt(x, y) { I.scrollPageToTop(); I.clickAt(this.stageBBox().x + x, this.stageBBox().y + y); I.waitTicks(3); // We gotta wait here because clicks on the canvas are not processed immediately }, dblClickAt(x, y) { I.scrollPageToTop(); I.dblClickAt(this.stageBBox().x + x, this.stageBBox().y + y); }, drawByClick(x, y) { I.scrollPageToTop(); this.clickAt(x, y); }, async clickOnRegion(regionIndex) { const regionId = await I.executeScript((regionIndex) => { const regions = Htx.annotationStore.selected.regions; return regions[regionIndex]?.cleanId ?? undefined; }, regionIndex); assert.notEqual(regionId, undefined, "Region not found"); const position = await this.getRegionAbsoultePosition(regionId, false); I.say("Clicking on a region at", `${position.x} ${position.y}`); this.clickAt(position.x, position.y); }, async dragRegion(regions, findIndex, shiftX = 50, shiftY = 50) { const region = regions.find(findIndex); assert.notEqual(region, undefined, "Region not found"); const position = await this.getRegionAbsoultePosition(region.id); I.say(`Drag region by ${shiftX} ${shiftY}`); await I.dragAndDropMouse(position, { x: position.x + shiftX, y: position.y + shiftY, }); }, selectPanTool() { I.say("Select pan tool"); I.pressKey("H"); }, selectMoveTool() { I.say("Select move tool"); I.pressKey("V"); }, selectToolByCode(toolCode) { I.click(this.locateToolByCode(toolCode)); }, hasSelectedTool(toolCode) { I.seeElement(`.lsf-tool_active${this.locateToolByCode(toolCode).toString()}`); }, async multiImageGoForwardWithHotkey() { I.say("Attempting to go to the next image"); I.pressKey("Ctrl+d"); await this.waitForImage(); }, async multiImageGoBackwardWithHotkey() { I.say("Attempting to go to the next image"); I.pressKey("Ctrl+a"); await this.waitForImage(); }, async multiImageGoForward() { I.click(this.locatePagination(this._paginationNextBtnSelector)); await this.waitForImage(); }, async multiImageGoBackward() { I.click(this.locatePagination(this._paginationPrevBtnSelector)); await this.waitForImage(); }, };