src/engine/tools2d/ToolText.js (111 lines of code) (raw):

/* * Copyright 2021 EPAM Systems, Inc. (https://www.epam.com/) * SPDX-License-Identifier: Apache-2.0 */ /** * @fileOverview ToolText * @author Epam * @version 1.0.0 */ // ********************************************** // Imports // ********************************************** import ToolDistance from './ToolDistance'; import StoreActionType from '../../store/ActionTypes'; // ********************************************** // Class // ********************************************** class ToolText { constructor(objGra) { this.m_objGraphics2d = objGra; this.m_wScreen = 0; this.m_hScreen = 0; this.m_texts = []; this.m_pointPressed = null; this.m_objEdit = null; this.m_xPixelSize = 0; this.m_yPixelSize = 0; this.onMouseDown = this.onMouseDown.bind(this); this.onMouseUp = this.onMouseUp.bind(this); this.onMouseMove = this.onMouseMove.bind(this); this.render = this.render.bind(this); this.setText = this.setText.bind(this); } setScreenDim(wScr, hScr) { this.m_wScreen = wScr; this.m_hScreen = hScr; } setPixelSize(xs, ys) { this.m_xPixelSize = xs; this.m_yPixelSize = ys; } /** * Determine intersection with points in all texts. * Input - screen coordinates of pick point * Output - volume coordinate * * @param {object} vScr - screen coordinates of poick * @param {object} store - global store */ getEditPoint(vScr, store) { const numTexts = this.m_texts.length; for (let i = 0; i < numTexts; i++) { const objText = this.m_texts[i]; const vScrProj = ToolDistance.textureToScreen(objText.point.x, objText.point.y, this.m_wScreen, this.m_hScreen, store); // Define the distance by "x" coordinate from the center of the text const MIN_DIST_X = objText.text.length * 4; // Define the distance by "y" coordinate from the text const MIN_DIST_Y = 16; // Check if the point is on the text if ( vScr.x >= vScrProj.x - MIN_DIST_X && vScr.x <= vScrProj.x + MIN_DIST_X && vScr.y >= vScrProj.y - MIN_DIST_Y && vScr.y <= vScrProj.y + MIN_DIST_Y ) { this.m_objEdit = objText; return objText.point; } } return null; } /** * Move edited point into new pos * * @param {object} vVolOld * @param {object} vVolNew */ moveEditPoint(vVolOld, vVolNew) { vVolOld.x = vVolNew.x; vVolOld.y = vVolNew.y; // update info about text } /** * Remove highlighted object * */ deleteObject() { if (this.m_objEdit != null) { const ind = this.m_texts.indexOf(this.m_objEdit); if (ind >= 0) { this.m_texts.splice(ind, 1); } } } getDistMm(vs, ve) { const dx = vs.x - ve.x; const dy = vs.y - ve.y; const dist = Math.sqrt(dx * dx * this.m_xPixelSize * this.m_xPixelSize + dy * dy * this.m_yPixelSize * this.m_yPixelSize); return dist; } setText(str) { const lines = str.split('\n'); const lineHeight = 16; const spacing = 4; for (let i = 0; i < lines.length; i++) { const objText = { point: { x: this.m_pointPressed.x, y: this.m_pointPressed.y + i * (lineHeight + spacing), }, text: lines[i], }; this.m_texts.push(objText); } // invoke render this.m_objGraphics2d.forceUpdate(); } clear() { this.m_texts = []; } /** * When mouse pressed down * * @param {number} xScr - x coordinate of click on screen * @param {number} yScr - y coordinate of click on screen * @param {object} store - global storage */ onMouseDown(xScr, yScr, store) { this.m_pointPressed = ToolDistance.screenToTexture(xScr, yScr, this.m_wScreen, this.m_hScreen, store); store.dispatch({ type: StoreActionType.SET_MODAL_TEXT, showModalText: true }); } onMouseMove() { // args ommited: xScr, yScr, store } onMouseUp() { // args ommited: xScr, yScr, store } /** * Render all areas on screen in 2d mode * * @param {object} ctx - html5 canvas context * @param {object} store - global store with app parameters */ render(ctx, store) { ctx.lineWidth = 2; ctx.strokeStyle = 'yellow'; ctx.fillStyle = 'white'; const FONT_SZ = 16; const LINE_HEIGHT = FONT_SZ * 1.2; // Added this line for line height calculation ctx.font = `${FONT_SZ}px Arial`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; // Changed from 'bottom' to 'middle' to better center multiline text const numTexts = this.m_texts.length; for (let i = 0; i < numTexts; i++) { const objText = this.m_texts[i]; const vTex = objText.point; const vScr = ToolDistance.textureToScreen(vTex.x, vTex.y, this.m_wScreen, this.m_hScreen, store); const lines = objText.text.split('\n'); // Split the text by newline character for (let j = 0; j < lines.length; j++) { ctx.fillText(lines[j], vScr.x, vScr.y + j * LINE_HEIGHT - ((lines.length - 1) * LINE_HEIGHT) / 2); } } // for (i) } // end render } // end class ToolText export default ToolText;