2021-07-17 14:36:39 +10:00
|
|
|
import Konva from "konva";
|
|
|
|
|
import { useRef, useEffect, useState } from "react";
|
2020-05-21 20:57:52 +10:00
|
|
|
import { Rect, Text, Group } from "react-konva";
|
|
|
|
|
|
2021-02-04 15:06:34 +11:00
|
|
|
import useSetting from "../../hooks/useSetting";
|
2021-07-17 14:36:39 +10:00
|
|
|
import { TokenState } from "../../types/TokenState";
|
2020-09-08 15:06:15 +10:00
|
|
|
|
2020-07-20 19:30:09 +10:00
|
|
|
const maxTokenSize = 3;
|
2021-06-20 12:48:52 +10:00
|
|
|
const defaultFontSize = 16;
|
2020-07-20 19:30:09 +10:00
|
|
|
|
2021-07-17 14:36:39 +10:00
|
|
|
type TokenLabelProps = {
|
|
|
|
|
tokenState: TokenState;
|
|
|
|
|
width: number;
|
|
|
|
|
height: number;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function TokenLabel({ tokenState, width, height }: TokenLabelProps) {
|
|
|
|
|
const [labelSize] = useSetting<number>("map.labelSize");
|
2020-09-08 15:06:15 +10:00
|
|
|
|
2020-07-20 19:30:09 +10:00
|
|
|
const paddingY =
|
2021-01-27 17:00:03 +11:00
|
|
|
(height / 12 / tokenState.size) * Math.min(tokenState.size, maxTokenSize);
|
2020-07-20 19:30:09 +10:00
|
|
|
const paddingX =
|
2021-01-27 17:00:03 +11:00
|
|
|
(height / 8 / tokenState.size) * Math.min(tokenState.size, maxTokenSize);
|
|
|
|
|
|
2021-06-20 12:48:52 +10:00
|
|
|
const [fontScale, setFontScale] = useState(0);
|
2021-01-27 17:00:03 +11:00
|
|
|
useEffect(() => {
|
|
|
|
|
const text = textSizerRef.current;
|
|
|
|
|
|
|
|
|
|
if (!text) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-17 14:36:39 +10:00
|
|
|
let fontSizes: number[] = [];
|
2021-06-20 12:48:52 +10:00
|
|
|
for (let size = 20 * labelSize; size >= 6; size--) {
|
|
|
|
|
const verticalSize = height / size / tokenState.size;
|
|
|
|
|
const tokenSize = Math.min(tokenState.size, maxTokenSize);
|
|
|
|
|
const fontSize = verticalSize * tokenSize * labelSize;
|
|
|
|
|
fontSizes.push(fontSize);
|
2021-01-27 17:00:03 +11:00
|
|
|
}
|
|
|
|
|
|
2021-07-17 14:36:39 +10:00
|
|
|
const findFontScale = () => {
|
2021-01-27 17:00:03 +11:00
|
|
|
const size = fontSizes.reduce((prev, curr) => {
|
|
|
|
|
text.fontSize(curr);
|
|
|
|
|
const textWidth = text.getTextWidth() + paddingX * 2;
|
|
|
|
|
if (textWidth < width) {
|
|
|
|
|
return curr;
|
|
|
|
|
} else {
|
|
|
|
|
return prev;
|
|
|
|
|
}
|
2021-06-20 12:48:52 +10:00
|
|
|
}, 1);
|
2021-01-27 17:00:03 +11:00
|
|
|
|
2021-06-20 12:48:52 +10:00
|
|
|
setFontScale(size / defaultFontSize);
|
2021-07-17 14:36:39 +10:00
|
|
|
};
|
2021-01-27 17:00:03 +11:00
|
|
|
|
2021-06-20 12:48:52 +10:00
|
|
|
findFontScale();
|
2021-04-11 13:49:29 +10:00
|
|
|
}, [
|
|
|
|
|
tokenState.label,
|
|
|
|
|
tokenState.visible,
|
|
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
tokenState,
|
|
|
|
|
labelSize,
|
|
|
|
|
paddingX,
|
|
|
|
|
]);
|
2020-05-21 20:57:52 +10:00
|
|
|
|
|
|
|
|
const [rectWidth, setRectWidth] = useState(0);
|
2021-06-20 12:48:52 +10:00
|
|
|
const [textWidth, setTextWidth] = useState(0);
|
2020-05-21 20:57:52 +10:00
|
|
|
useEffect(() => {
|
|
|
|
|
const text = textRef.current;
|
|
|
|
|
if (text && tokenState.label) {
|
2021-06-20 12:48:52 +10:00
|
|
|
setRectWidth(text.getTextWidth() * fontScale + paddingX * 2);
|
|
|
|
|
setTextWidth(text.getTextWidth() * fontScale);
|
2020-05-21 20:57:52 +10:00
|
|
|
} else {
|
|
|
|
|
setRectWidth(0);
|
2021-06-20 12:48:52 +10:00
|
|
|
setTextWidth(0);
|
2020-05-21 20:57:52 +10:00
|
|
|
}
|
2021-06-20 12:48:52 +10:00
|
|
|
}, [tokenState.label, paddingX, width, fontScale]);
|
2020-05-21 20:57:52 +10:00
|
|
|
|
2021-07-17 14:36:39 +10:00
|
|
|
const textRef = useRef<Konva.Text>(null);
|
|
|
|
|
const textSizerRef = useRef<Konva.Text>(null);
|
2020-04-13 00:24:03 +10:00
|
|
|
|
|
|
|
|
return (
|
2021-06-20 12:48:52 +10:00
|
|
|
<Group y={height - (defaultFontSize * fontScale + paddingY) / 2}>
|
2020-05-21 20:57:52 +10:00
|
|
|
<Rect
|
|
|
|
|
y={-paddingY / 2}
|
|
|
|
|
width={rectWidth}
|
|
|
|
|
offsetX={width / 2}
|
|
|
|
|
x={width - rectWidth / 2}
|
2021-06-20 12:48:52 +10:00
|
|
|
height={defaultFontSize * fontScale + paddingY}
|
2020-05-21 20:57:52 +10:00
|
|
|
fill="hsla(230, 25%, 18%, 0.8)"
|
2021-06-20 12:48:52 +10:00
|
|
|
cornerRadius={(defaultFontSize * fontScale + paddingY) / 2}
|
2020-05-21 20:57:52 +10:00
|
|
|
/>
|
2021-06-20 12:48:52 +10:00
|
|
|
<Group offsetX={(textWidth - width) / 2}>
|
|
|
|
|
<Text
|
|
|
|
|
ref={textRef}
|
|
|
|
|
text={tokenState.label}
|
|
|
|
|
fontSize={defaultFontSize}
|
|
|
|
|
lineHeight={1}
|
|
|
|
|
// Scale font instead of changing font size to avoid kerning issues with Firefox
|
|
|
|
|
scaleX={fontScale}
|
|
|
|
|
scaleY={fontScale}
|
|
|
|
|
fill="white"
|
|
|
|
|
wrap="none"
|
|
|
|
|
ellipsis={false}
|
|
|
|
|
hitFunc={() => {}}
|
|
|
|
|
/>
|
|
|
|
|
</Group>
|
2021-01-27 17:00:03 +11:00
|
|
|
{/* Use an invisible text block to work out text sizing */}
|
|
|
|
|
<Text
|
|
|
|
|
visible={false}
|
|
|
|
|
ref={textSizerRef}
|
|
|
|
|
text={tokenState.label}
|
|
|
|
|
wrap="none"
|
|
|
|
|
/>
|
2020-05-21 20:57:52 +10:00
|
|
|
</Group>
|
2020-04-13 00:24:03 +10:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default TokenLabel;
|