Compare commits
2 Commits
4c3d83922f
...
bd2e7ac5a5
| Author | SHA1 | Date |
|---|---|---|
|
|
bd2e7ac5a5 | |
|
|
63c320f669 |
|
|
@ -6,13 +6,7 @@ customElement("md-pin", { x: 0, y: 0 }, (props, { element }) => {
|
||||||
|
|
||||||
const [position, setPosition] = createSignal<{ top: string; left: string }>({ top: "0", left: "0" });
|
const [position, setPosition] = createSignal<{ top: string; left: string }>({ top: "0", left: "0" });
|
||||||
const [visible, setVisible] = createSignal(false);
|
const [visible, setVisible] = createSignal(false);
|
||||||
const [containerStyle, setContainerStyle] = createSignal<{ position: string; top: string; left: string; width: string; height: string }>({
|
const [transformStyle, setTransformStyle] = createSignal<string>("");
|
||||||
position: "absolute",
|
|
||||||
top: "0",
|
|
||||||
left: "0",
|
|
||||||
width: "0",
|
|
||||||
height: "0"
|
|
||||||
});
|
|
||||||
const [showToast, setShowToast] = createSignal(false);
|
const [showToast, setShowToast] = createSignal(false);
|
||||||
const [toastMessage, setToastMessage] = createSignal("");
|
const [toastMessage, setToastMessage] = createSignal("");
|
||||||
let pinContainer: HTMLSpanElement | undefined;
|
let pinContainer: HTMLSpanElement | undefined;
|
||||||
|
|
@ -57,23 +51,14 @@ customElement("md-pin", { x: 0, y: 0 }, (props, { element }) => {
|
||||||
if (!targetImage || !pinContainer) return;
|
if (!targetImage || !pinContainer) return;
|
||||||
|
|
||||||
const imgRect = targetImage.getBoundingClientRect();
|
const imgRect = targetImage.getBoundingClientRect();
|
||||||
const articleEl = element?.closest('article[data-src]');
|
const containerRect = pinContainer.parentElement.getBoundingClientRect();
|
||||||
const articleRect = articleEl?.getBoundingClientRect();
|
|
||||||
|
|
||||||
if (!articleRect) return;
|
// 计算图片左上角相对于容器原始位置的偏移
|
||||||
|
const offsetX = imgRect.left - containerRect.left;
|
||||||
|
const offsetY = imgRect.top - containerRect.top;
|
||||||
|
|
||||||
// 计算图片相对于 article 的位置
|
// 使用 transform 将容器移动到图片位置
|
||||||
const relativeTop = imgRect.top - articleRect.top;
|
setTransformStyle(`translate(${offsetX}px, ${offsetY}px)`);
|
||||||
const relativeLeft = imgRect.left - articleRect.left;
|
|
||||||
|
|
||||||
// 设置容器样式,使其定位到图片位置
|
|
||||||
setContainerStyle({
|
|
||||||
position: "absolute",
|
|
||||||
top: `${relativeTop}px`,
|
|
||||||
left: `${relativeLeft}px`,
|
|
||||||
width: `${imgRect.width}px`,
|
|
||||||
height: `${imgRect.height}px`
|
|
||||||
});
|
|
||||||
|
|
||||||
// 计算 pin 在图片内的相对位置(x/y 是百分比)
|
// 计算 pin 在图片内的相对位置(x/y 是百分比)
|
||||||
const x = typeof props.x === 'number' ? props.x : parseFloat(props.x) || 0;
|
const x = typeof props.x === 'number' ? props.x : parseFloat(props.x) || 0;
|
||||||
|
|
@ -93,15 +78,6 @@ customElement("md-pin", { x: 0, y: 0 }, (props, { element }) => {
|
||||||
targetImage = findNearestImage();
|
targetImage = findNearestImage();
|
||||||
|
|
||||||
if (targetImage) {
|
if (targetImage) {
|
||||||
// 确保图片容器是 relative 定位
|
|
||||||
const imgParent = targetImage.parentElement;
|
|
||||||
if (imgParent) {
|
|
||||||
const parentStyle = window.getComputedStyle(imgParent);
|
|
||||||
if (parentStyle.position === 'static') {
|
|
||||||
imgParent.style.position = 'relative';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始定位
|
// 初始定位
|
||||||
updatePosition();
|
updatePosition();
|
||||||
|
|
||||||
|
|
@ -126,42 +102,11 @@ customElement("md-pin", { x: 0, y: 0 }, (props, { element }) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理点击,报告坐标并复制到剪贴板
|
|
||||||
const handleClick = (e: MouseEvent) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
if (!targetImage) return;
|
|
||||||
|
|
||||||
const imgRect = targetImage.getBoundingClientRect();
|
|
||||||
|
|
||||||
// 计算点击位置相对于图片的百分比
|
|
||||||
const clickX = ((e.clientX - imgRect.left) / imgRect.width) * 100;
|
|
||||||
const clickY = ((e.clientY - imgRect.top) / imgRect.height) * 100;
|
|
||||||
|
|
||||||
// 四舍五入到整数
|
|
||||||
const x = Math.round(clickX);
|
|
||||||
const y = Math.round(clickY);
|
|
||||||
|
|
||||||
// 生成格式化的坐标字符串
|
|
||||||
const coordText = `:md-pin[${label || ''}]{x=${x} y=${y}}`;
|
|
||||||
|
|
||||||
// 复制到剪贴板
|
|
||||||
navigator.clipboard.writeText(coordText).then(() => {
|
|
||||||
setToastMessage(`已复制:${coordText}`);
|
|
||||||
setShowToast(true);
|
|
||||||
setTimeout(() => setShowToast(false), 2000);
|
|
||||||
}).catch(err => {
|
|
||||||
console.error('复制失败:', err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<div
|
||||||
ref={pinContainer}
|
ref={pinContainer}
|
||||||
class="md-pin-container"
|
class="md-pin-container"
|
||||||
style={{ display: 'inline', position: containerStyle().position, top: containerStyle().top, left: containerStyle().left, width: containerStyle().width, height: containerStyle().height }}
|
style={{ transform: transformStyle(), 'transform-origin': 'top left' }}
|
||||||
onClick={handleClick}
|
|
||||||
>
|
>
|
||||||
<Show when={visible() && targetImage}>
|
<Show when={visible() && targetImage}>
|
||||||
<span
|
<span
|
||||||
|
|
@ -183,6 +128,6 @@ customElement("md-pin", { x: 0, y: 0 }, (props, { element }) => {
|
||||||
{toastMessage()}
|
{toastMessage()}
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</span>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
|
||||||
<Show when={props.roll}>
|
<Show when={props.roll}>
|
||||||
<button
|
<button
|
||||||
onClick={handleRoll}
|
onClick={handleRoll}
|
||||||
class="text-gray-500 hover:text-gray-700 flex-shrink-0"
|
class="text-gray-500 hover:text-gray-700 flex-shrink-0 cursor-pointer"
|
||||||
title="随机切换"
|
title="随机切换"
|
||||||
>
|
>
|
||||||
🎲
|
🎲
|
||||||
|
|
@ -197,7 +197,7 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
|
||||||
{(row, index) => (
|
{(row, index) => (
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveTab(index())}
|
onClick={() => setActiveTab(index())}
|
||||||
class={`font-medium transition-colors flex-shrink-0 min-w-[1.6em] ${
|
class={`font-medium transition-colors flex-shrink-0 min-w-[1.6em] cursor-pointer ${
|
||||||
activeTab() === index()
|
activeTab() === index()
|
||||||
? 'text-blue-600 border-b-2 border-blue-600'
|
? 'text-blue-600 border-b-2 border-blue-600'
|
||||||
: 'text-gray-500 hover:text-gray-700'
|
: 'text-gray-500 hover:text-gray-700'
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue