2024-07-23 12:53:12 -05:00
|
|
|
import {RESOLUTION} from '@/util/constants.js';
|
|
|
|
|
|
|
|
import styles from './dialogue-caret.module.css';
|
|
|
|
|
|
|
|
const CARET_SIZE = 18;
|
|
|
|
|
|
|
|
export default function DialogueCaret({
|
|
|
|
camera,
|
|
|
|
dialogue,
|
|
|
|
dimensions,
|
|
|
|
scale,
|
|
|
|
}) {
|
|
|
|
const origin = 'function' === typeof dialogue.origin
|
|
|
|
? dialogue.origin()
|
|
|
|
: dialogue.origin || {x: 0, y: 0};
|
|
|
|
let position = 'function' === typeof dialogue.position
|
|
|
|
? dialogue.position()
|
|
|
|
: dialogue.position || {x: 0, y: 0};
|
|
|
|
position = {
|
|
|
|
x: position.x + dialogue.offset.x,
|
|
|
|
y: position.y + dialogue.offset.y,
|
|
|
|
};
|
|
|
|
const bounds = {
|
|
|
|
x: dimensions.w / (2 * scale),
|
|
|
|
y: dimensions.h / (2 * scale),
|
|
|
|
};
|
|
|
|
const left = Math.max(
|
|
|
|
Math.min(
|
2024-07-30 14:05:27 -05:00
|
|
|
position.x * scale,
|
|
|
|
RESOLUTION.x - bounds.x * scale - 16 + camera.x,
|
2024-07-23 12:53:12 -05:00
|
|
|
),
|
2024-07-30 14:05:27 -05:00
|
|
|
bounds.x * scale + 16 + camera.x,
|
2024-07-23 12:53:12 -05:00
|
|
|
);
|
|
|
|
const top = Math.max(
|
|
|
|
Math.min(
|
2024-07-30 14:05:27 -05:00
|
|
|
position.y * scale - dimensions.h / 2,
|
|
|
|
RESOLUTION.y - bounds.y * scale - 16 + camera.y,
|
2024-07-23 12:53:12 -05:00
|
|
|
),
|
2024-07-30 14:05:27 -05:00
|
|
|
bounds.y * scale + 16 + camera.y,
|
2024-07-23 12:53:12 -05:00
|
|
|
);
|
|
|
|
const offsetPosition = {
|
2024-07-30 14:05:27 -05:00
|
|
|
x: ((position.x * scale) - left) / scale,
|
|
|
|
y: ((position.y * scale) - top) / scale,
|
2024-07-23 12:53:12 -05:00
|
|
|
};
|
|
|
|
const difference = {
|
|
|
|
x: origin.x - position.x + offsetPosition.x,
|
|
|
|
y: origin.y - position.y + offsetPosition.y,
|
|
|
|
};
|
|
|
|
const within = {
|
|
|
|
x: Math.abs(difference.x) < bounds.x,
|
|
|
|
y: Math.abs(difference.y) < bounds.y,
|
|
|
|
};
|
|
|
|
const caretPosition = {
|
|
|
|
x: Math.max(-bounds.x, Math.min(origin.x - position.x + offsetPosition.x, bounds.x)),
|
|
|
|
y: Math.max(-bounds.y, Math.min(origin.y - position.y + offsetPosition.y, bounds.y)),
|
|
|
|
};
|
|
|
|
let caretRotation = Math.atan2(
|
|
|
|
difference.y - caretPosition.y,
|
|
|
|
difference.x - caretPosition.x,
|
|
|
|
);
|
|
|
|
caretRotation += Math.PI * 1.5;
|
|
|
|
if (within.x) {
|
|
|
|
caretPosition.y = bounds.y * Math.sign(difference.y);
|
|
|
|
if (within.y) {
|
|
|
|
if (Math.sign(difference.y) > 0) {
|
|
|
|
caretRotation = Math.PI;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
caretRotation = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (within.y) {
|
|
|
|
caretPosition.x = bounds.x * Math.sign(difference.x);
|
|
|
|
}
|
|
|
|
// const corner = {
|
|
|
|
// x: (bounds.x - Math.abs(caretPosition.x)) * Math.sign(caretPosition.x),
|
|
|
|
// y: (bounds.y - Math.abs(caretPosition.y)) * Math.sign(caretPosition.y),
|
|
|
|
// };
|
|
|
|
caretPosition.x *= scale;
|
|
|
|
caretPosition.y *= scale;
|
|
|
|
caretPosition.x += -Math.sin(caretRotation) * (CARET_SIZE / 2);
|
|
|
|
caretPosition.y += Math.cos(caretRotation) * (CARET_SIZE / 2);
|
|
|
|
return (
|
|
|
|
<svg
|
|
|
|
className={styles.caret}
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
width={CARET_SIZE}
|
|
|
|
height={CARET_SIZE}
|
|
|
|
style={{
|
|
|
|
transform: `
|
|
|
|
translate(
|
|
|
|
calc(-50% + ${caretPosition.x}px),
|
|
|
|
calc(-50% + ${caretPosition.y}px)
|
|
|
|
)
|
|
|
|
rotate(${caretRotation}rad)
|
|
|
|
`,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<polygon points="12 0, 18 10, 12 23, 23 10, 20 0" />
|
|
|
|
</svg>
|
|
|
|
);
|
|
|
|
}
|