Skip to content

Commit

Permalink
improve calc-text-width method reusing the Konva canvas
Browse files Browse the repository at this point in the history
  • Loading branch information
Alber-Writer committed Nov 14, 2024
1 parent f3f7bef commit b88a23b
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -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;
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Layer } from 'konva/lib/Layer';
import { balanceSpacePerItem } from './balance-space';
import { calcTextWidth } from './calc-text-width';

Expand All @@ -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 =
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
extractCSVHeaders,
splitCSVContentIntoRows,
} from '@/common/utils/active-element-selector.utils';
import { useCanvasContext } from '@/core/providers';

interface TabListConfig {
text: string;
Expand All @@ -28,6 +29,8 @@ export const useTabList = (tabsConfig: TabListConfig) => {

const tabLabels = _extractTabLabelTexts(text);

const konvaLayer = useCanvasContext().stageRef.current?.getLayers()[0];

useEffect(() => {
setTabWidthList(
adjustTabWidths({
Expand All @@ -40,6 +43,7 @@ export const useTabList = (tabsConfig: TabListConfig) => {
fontSize: font.fontSize,
fontFamily: font.fontFamily,
},
konvaLayer,
})
);
}, [text, containerWidth]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ export const TabsBarShape = forwardRef<any, ShapeProps>((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({
Expand Down Expand Up @@ -79,7 +79,8 @@ export const TabsBarShape = forwardRef<any, ShapeProps>((props, ref) => {
{/* Map through headerRow to create tabs */}
{tabList.map(({ tab, width, xPos }, index) => {
return (
<Group key={index} x={10 + xPos} y={10}>
<Group key={index} x={10 + xPos || 0} y={10}>
{/* || 0 Workaround to avoid thumbpage NaN issue with konva */}
<Rect
width={width}
height={tabHeight}
Expand All @@ -90,7 +91,9 @@ export const TabsBarShape = forwardRef<any, ShapeProps>((props, ref) => {
<Text
x={tabXPadding}
y={8}
width={width - tabXPadding * 2}
width={
width - tabXPadding * 2 || 0
} /* || 0 Workaround to avoid thumbpage NaN issue with konva */
height={tabHeight}
ellipsis={true}
wrap="none"
Expand Down

0 comments on commit b88a23b

Please sign in to comment.