From b88a23b4835eec1cff5cbb77a1368c23c24b5f6b Mon Sep 17 00:00:00 2001 From: Alber EE <122263897+Alber-Writer@users.noreply.github.com> Date: Thu, 14 Nov 2024 23:21:43 +0100 Subject: [PATCH] improve calc-text-width method reusing the Konva canvas --- .../tabsbar/business/calc-text-width.ts | 42 +++++++++++++++++-- .../tabsbar/business/tabsbar.business.ts | 16 +++++-- .../tabsbar/tab-list.hook.ts | 4 ++ .../tabsbar/tabsbar-shape.tsx | 13 +++--- 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/common/components/mock-components/front-rich-components/tabsbar/business/calc-text-width.ts b/src/common/components/mock-components/front-rich-components/tabsbar/business/calc-text-width.ts index f83a5fbe..843bd15e 100644 --- a/src/common/components/mock-components/front-rich-components/tabsbar/business/calc-text-width.ts +++ b/src/common/components/mock-components/front-rich-components/tabsbar/business/calc-text-width.ts @@ -1,16 +1,50 @@ +import { Layer } from 'konva/lib/Layer'; + +/** + * Virtually calculates the width that a text will occupy, by using a canvas. + * If a Konva Layer is provided, it will reuse the already existing canvas. + * Otherwise, it will create a canvas within the document, on the fly, to perform the measurement. + * Finaly, as a safety net, a very generic calculation is provided in case the other options are not available. + */ export const calcTextWidth = ( inputText: string, fontSize: number, + fontfamily: string, + konvaLayer?: Layer +) => { + if (konvaLayer) + return _getTextWidthByKonvaMethod( + konvaLayer, + inputText, + fontSize, + fontfamily + ); + + return _getTextCreatingNewCanvas(inputText, fontSize, fontfamily); +}; + +const _getTextWidthByKonvaMethod = ( + konvaLayer: Layer, + text: string, + fontSize: number, + fontfamily: string +) => { + const context = konvaLayer.getContext(); + context.font = `${fontSize}px ${fontfamily}`; + return context.measureText(text).width; +}; + +const _getTextCreatingNewCanvas = ( + text: string, + fontSize: number, fontfamily: string ) => { - // Creates an invisible canvas to perform the measurement let canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); - if (context) { context.font = `${fontSize}px ${fontfamily}`; - return context.measureText(inputText).width; + return context.measureText(text).width; } const charAverageWidth = fontSize * 0.7; - return inputText.length * charAverageWidth + charAverageWidth * 0.8; + return text.length * charAverageWidth + charAverageWidth * 0.8; }; diff --git a/src/common/components/mock-components/front-rich-components/tabsbar/business/tabsbar.business.ts b/src/common/components/mock-components/front-rich-components/tabsbar/business/tabsbar.business.ts index da48e9ea..ce08f8bb 100644 --- a/src/common/components/mock-components/front-rich-components/tabsbar/business/tabsbar.business.ts +++ b/src/common/components/mock-components/front-rich-components/tabsbar/business/tabsbar.business.ts @@ -1,3 +1,4 @@ +import { Layer } from 'konva/lib/Layer'; import { balanceSpacePerItem } from './balance-space'; import { calcTextWidth } from './calc-text-width'; @@ -11,9 +12,17 @@ export const adjustTabWidths = (args: { fontSize: number; fontFamily: string; }; + konvaLayer?: Layer; }) => { - const { tabs, containerWidth, minTabWidth, tabXPadding, tabsGap, font } = - args; + const { + tabs, + containerWidth, + minTabWidth, + tabXPadding, + tabsGap, + font, + konvaLayer, + } = args; const totalInnerXPadding = tabXPadding * 2; const totalMinTabSpace = minTabWidth + totalInnerXPadding; const containerWidthWithoutTabGaps = @@ -27,7 +36,8 @@ export const adjustTabWidths = (args: { const arrangeTabsInfo = tabs.reduce( (acc: OriginalTabInfo[], tab, index): OriginalTabInfo[] => { const tabFullTextWidth = - calcTextWidth(tab, font.fontSize, font.fontFamily) + totalInnerXPadding; + calcTextWidth(tab, font.fontSize, font.fontFamily, konvaLayer) + + totalInnerXPadding; const desiredWidth = Math.max(totalMinTabSpace, tabFullTextWidth); return [ ...acc, diff --git a/src/common/components/mock-components/front-rich-components/tabsbar/tab-list.hook.ts b/src/common/components/mock-components/front-rich-components/tabsbar/tab-list.hook.ts index a4c6694f..e115f4c2 100644 --- a/src/common/components/mock-components/front-rich-components/tabsbar/tab-list.hook.ts +++ b/src/common/components/mock-components/front-rich-components/tabsbar/tab-list.hook.ts @@ -4,6 +4,7 @@ import { extractCSVHeaders, splitCSVContentIntoRows, } from '@/common/utils/active-element-selector.utils'; +import { useCanvasContext } from '@/core/providers'; interface TabListConfig { text: string; @@ -28,6 +29,8 @@ export const useTabList = (tabsConfig: TabListConfig) => { const tabLabels = _extractTabLabelTexts(text); + const konvaLayer = useCanvasContext().stageRef.current?.getLayers()[0]; + useEffect(() => { setTabWidthList( adjustTabWidths({ @@ -40,6 +43,7 @@ export const useTabList = (tabsConfig: TabListConfig) => { fontSize: font.fontSize, fontFamily: font.fontFamily, }, + konvaLayer, }) ); }, [text, containerWidth]); diff --git a/src/common/components/mock-components/front-rich-components/tabsbar/tabsbar-shape.tsx b/src/common/components/mock-components/front-rich-components/tabsbar/tabsbar-shape.tsx index aabd65b7..d76cb6cf 100644 --- a/src/common/components/mock-components/front-rich-components/tabsbar/tabsbar-shape.tsx +++ b/src/common/components/mock-components/front-rich-components/tabsbar/tabsbar-shape.tsx @@ -40,10 +40,10 @@ export const TabsBarShape = forwardRef((props, ref) => { const { width: restrictedWidth, height: restrictedHeight } = restrictedSize; // Tab dimensions and margin - const tabHeight = 30; // Tab height - const tabsGap = 10; // Horizontal margin between tabs + const tabHeight = 30; + const tabsGap = 10; const tabXPadding = 20; - const tabFont = { fontSize: 14, fontFamily: 'Arial' }; + const tabFont = { fontSize: 14, fontFamily: 'Arial, sans-serif' }; const bodyHeight = restrictedHeight - tabHeight - 10; // Height of the tabs bar body const tabList = useTabList({ @@ -79,7 +79,8 @@ export const TabsBarShape = forwardRef((props, ref) => { {/* Map through headerRow to create tabs */} {tabList.map(({ tab, width, xPos }, index) => { return ( - + + {/* || 0 Workaround to avoid thumbpage NaN issue with konva */} ((props, ref) => {