Files
dsProject/dsLightRag/static/XingJun/js/script.js
2025-09-10 07:52:32 +08:00

432 lines
17 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 添加常量定义
const ARROW_WIDTH = 155;
const ARROW_HEIGHT = 173;
const STOP_DISTANCE = 50;
document.addEventListener('DOMContentLoaded', function() {
const backgroundContainer = document.querySelector('.background-container');
const imageButtons = document.querySelectorAll('.image-btn');
const markCenterBtn = document.getElementById('markCenterBtn');
const startAnimationBtn = document.getElementById('startAnimationBtn');
const resetBtn = document.getElementById('resetBtn');
const contextMenu = document.getElementById('contextMenu');
const deleteArrow = document.getElementById('deleteArrow');
let selectedArrow = null;
let centerDot = null;
// 添加重置按钮事件监听器
resetBtn.addEventListener('click', function() {
location.reload();
});
// 添加开始按钮事件监听器
startAnimationBtn.addEventListener('click', startAnimation);
// 动画控制函数
function startAnimation() {
if (!centerDot) {
alert('请先确定中心点');
return;
}
const centerRect = centerDot.getBoundingClientRect();
const containerRect = backgroundContainer.getBoundingClientRect();
const centerX = centerRect.left - containerRect.left;
const centerY = centerRect.top - containerRect.top;
const arrows = document.querySelectorAll('.arrow-container');
if (arrows.length === 0) {
alert('没有可移动的箭头');
return;
}
arrows.forEach(arrow => {
animateArrow(arrow, centerX, centerY);
});
}
// 修改全局偏移量输入框事件监听
// 删除以下全局停止距离相关代码
// const globalStopDistanceInput = document.getElementById('global-stop-distance');
//
// // 初始化全局偏移量(从localStorage加载或使用默认值)
// const savedGlobalStopDistance = localStorage.getItem('globalStopDistance');
// if (savedGlobalStopDistance) {
// globalStopDistanceInput.value = savedGlobalStopDistance;
// }
//
// // 全局偏移量变更事件 - 保存到localStorage无需选中箭头
// globalStopDistanceInput.addEventListener('input', function() {
// const globalValue = this.value;
// localStorage.setItem('globalStopDistance', globalValue);
// console.log(`[全局设置] 箭头停止距离: ${globalValue}px`);
// });
// 单个箭头动画函数
function animateArrow(arrow, targetX, targetY) {
const arrowWidth = ARROW_WIDTH;
const arrowHeight = ARROW_HEIGHT;
const centerOffsetX = arrowWidth / 2;
const centerOffsetY = arrowHeight / 2;
// 使用当前箭头的停止距离默认为50
const stopDistance = parseInt(arrow.dataset.stopDistance) || 50;
const rect = arrow.getBoundingClientRect();
const containerRect = backgroundContainer.getBoundingClientRect();
let currentX = rect.left - containerRect.left + centerOffsetX;
let currentY = rect.top - containerRect.top + centerOffsetY;
const offsetRange = 20;
const randomOffsetX = (Math.random() - 0.5) * offsetRange;
const randomOffsetY = (Math.random() - 0.5) * offsetRange;
const finalTargetX = targetX + randomOffsetX;
const finalTargetY = targetY + randomOffsetY;
const dxTotal = finalTargetX - currentX;
const dyTotal = finalTargetY - currentY;
const distanceTotal = Math.sqrt(dxTotal * dxTotal + dyTotal * dyTotal);
let adjustedTargetX, adjustedTargetY;
if (distanceTotal > stopDistance) {
const ratio = (distanceTotal - stopDistance) / distanceTotal;
adjustedTargetX = currentX + dxTotal * ratio;
adjustedTargetY = currentY + dyTotal * ratio;
} else {
adjustedTargetX = currentX;
adjustedTargetY = currentY;
}
function updatePosition() {
const dx = adjustedTargetX - currentX;
const dy = adjustedTargetY - currentY;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 2) {
arrow.style.left = (adjustedTargetX - centerOffsetX) + 'px';
arrow.style.top = (adjustedTargetY - centerOffsetY) + 'px';
return;
}
const step = Math.max(distance * 0.05, 1);
const moveX = (dx / distance) * step;
const moveY = (dy / distance) * step;
currentX += moveX;
currentY += moveY;
arrow.style.left = (currentX - centerOffsetX) + 'px';
arrow.style.top = (currentY - centerOffsetY) + 'px';
requestAnimationFrame(updatePosition);
}
updatePosition();
}
// 加载保存的元素
loadAllElements();
// 绑定箭头按钮事件
imageButtons.forEach(button => {
button.addEventListener('click', () => {
const imagePath = button.getAttribute('data-image');
addImageToContainer(imagePath);
});
});
// 右键菜单事件
deleteArrow.addEventListener('click', function() {
if (selectedArrow) {
selectedArrow.remove();
saveAllElements();
contextMenu.style.display = 'none';
selectedArrow = null;
}
});
// 为匹配角菜单项添加事件监听器
document.querySelectorAll('.menu-item').forEach(item => {
item.addEventListener('click', function() {
if (selectedArrow) {
const referencePoint = this.getAttribute('data-point');
selectedArrow.dataset.referencePoint = referencePoint;
saveAllElements();
contextMenu.style.display = 'none';
selectedArrow = null;
}
});
});
// 点击空白处关闭菜单
document.addEventListener('click', function() {
contextMenu.style.display = 'none';
selectedArrow = null;
});
// 标记中心点功能
markCenterBtn.addEventListener('click', function() {
if (centerDot) {
centerDot.remove();
centerDot = null;
}
function handleMapClick(e) {
const rect = backgroundContainer.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
centerDot = document.createElement('div');
centerDot.className = 'center-dot';
centerDot.style.left = x + 'px';
centerDot.style.top = y + 'px';
backgroundContainer.appendChild(centerDot);
backgroundContainer.removeEventListener('click', handleMapClick);
console.log('[中心点] 已标记中心点:', { left: centerDot.style.left, top: centerDot.style.top });
saveAllElements();
}
backgroundContainer.addEventListener('click', handleMapClick);
});
// 添加箭头函数
function addImageToContainer(imagePath, position = null, textContent = '') {
const container = document.createElement('div');
container.className = 'arrow-container';
container.dataset.imagePath = imagePath;
const newImage = document.createElement('div');
newImage.className = 'arrow-image';
newImage.style.backgroundImage = `url('${imagePath}')`;
container.appendChild(newImage);
// 添加文字元素
if (textContent) {
const textElement = document.createElement('div');
textElement.className = 'arrow-text';
textElement.textContent = textContent;
container.dataset.text = textContent;
container.appendChild(textElement);
}
// 设置位置
const arrowWidth = ARROW_WIDTH;
const arrowHeight = ARROW_HEIGHT;
const centerOffsetX = arrowWidth / 2;
const centerOffsetY = arrowHeight / 2;
if (position) {
container.style.left = parseFloat(position.left) + 'px';
container.style.top = parseFloat(position.top) + 'px';
if (position.referencePoint) {
container.dataset.referencePoint = position.referencePoint;
}
if (position.stopDistance) {
container.dataset.stopDistance = position.stopDistance;
}
} else {
const x = Math.random() * (backgroundContainer.offsetWidth - arrowWidth) + centerOffsetX;
const y = Math.random() * (backgroundContainer.offsetHeight - arrowHeight) + centerOffsetY;
container.style.left = (x - centerOffsetX) + 'px';
container.style.top = (y - centerOffsetY) + 'px';
}
// 双击编辑文字和停止距离
container.addEventListener('dblclick', (e) => {
e.stopPropagation();
const currentText = container.dataset.text || '';
const currentStopDistance = container.dataset.stopDistance || '50';
// 创建自定义弹窗内容使用layui表单样式
const content = `
<div style="padding: 20px;">
<div class="layui-form-item">
<label class="layui-form-label">文字内容:</label>
<div class="layui-input-block">
<input type="text" id="arrowText" value="${currentText}" class="layui-input" style="width: 100%;">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">停止距离 (px):</label>
<div class="layui-input-block">
<input type="number" id="arrowStopDistance" value="${currentStopDistance}" min="0" max="200" class="layui-input" style="width: 100%;">
</div>
</div>
</div>
`;
// 使用layer.open创建自定义弹窗增加宽度并应用layui样式
layer.open({
type: 1,
title: '编辑箭头属性',
area: ['500px', 'auto'], // 增加宽度到500px
content: content,
btn: ['确定', '取消'],
skin: 'layui-layer-molv', // 使用layui默认皮肤
success: function(layero) {
// 初始化layui表单样式
layui.form.render(null, 'arrowForm');
},
yes: function(index, layero) {
const textValue = layero.find('#arrowText').val().trim();
const stopDistanceValue = layero.find('#arrowStopDistance').val();
// 保存文字内容
if (textValue === '') {
container.querySelector('.arrow-text')?.remove();
delete container.dataset.text;
} else {
let textElement = container.querySelector('.arrow-text');
if (!textElement) {
textElement = document.createElement('div');
textElement.className = 'arrow-text';
container.appendChild(textElement);
}
textElement.textContent = textValue;
container.dataset.text = textValue;
}
// 保存停止距离
if (!isNaN(stopDistanceValue) && stopDistanceValue >= 0) {
container.dataset.stopDistance = stopDistanceValue;
}
saveAllElements();
layer.close(index);
}
});
});
// 右键菜单支持
container.addEventListener('contextmenu', function(e) {
e.preventDefault();
selectedArrow = this;
contextMenu.style.left = `${e.clientX}px`;
contextMenu.style.top = `${e.clientY}px`;
contextMenu.style.display = 'block';
const currentPoint = selectedArrow.dataset.referencePoint || 'top-left';
document.querySelectorAll('.menu-item').forEach(item => {
const checkMark = item.querySelector('.check-mark');
if (!checkMark) return;
checkMark.textContent = item.getAttribute('data-point') === currentPoint ? '✓' : '';
});
});
// 拖拽功能
let isDragging = false;
let offsetX, offsetY;
newImage.addEventListener('mousedown', startDrag);
function startDrag(e) {
e.preventDefault();
isDragging = true;
selectedArrow = container;
container.style.zIndex = '10';
const rect = container.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', stopDrag);
}
function drag(e) {
if (!isDragging) return;
const containerRect = backgroundContainer.getBoundingClientRect();
const x = e.clientX - containerRect.left - offsetX;
const y = e.clientY - containerRect.top - offsetY;
container.style.left = x + 'px';
container.style.top = y + 'px';
}
function stopDrag() {
if (isDragging) {
isDragging = false;
container.style.zIndex = '1';
saveAllElements();
document.removeEventListener('mousemove', drag);
document.removeEventListener('mouseup', stopDrag);
}
}
backgroundContainer.appendChild(container);
saveAllElements();
return container;
}
// 保存所有元素状态
function saveAllElements() {
const elements = [];
// 保存中心点
if (centerDot) {
localStorage.setItem('centerPoint', JSON.stringify({
left: centerDot.style.left,
top: centerDot.style.top
}));
} else {
localStorage.removeItem('centerPoint');
}
// 删除全局停止距离的保存
localStorage.removeItem('globalStopDistance');
// 保存箭头(添加stopDistance属性)
document.querySelectorAll('.arrow-container').forEach(arrow => {
elements.push({
type: 'arrow',
imagePath: arrow.dataset.imagePath,
left: arrow.style.left,
top: arrow.style.top,
text: arrow.dataset.text || '',
referencePoint: arrow.dataset.referencePoint || 'top-left',
stopDistance: arrow.dataset.stopDistance || '50' // 添加停止距离保存
});
});
localStorage.setItem('savedElements', JSON.stringify(elements));
console.log('[保存] 已保存元素:', elements);
}
// 加载所有元素状态
function loadAllElements() {
// 加载中心点
const savedCenter = localStorage.getItem('centerPoint');
if (savedCenter) {
const center = JSON.parse(savedCenter);
centerDot = document.createElement('div');
centerDot.className = 'center-dot';
centerDot.style.left = center.left;
centerDot.style.top = center.top;
backgroundContainer.appendChild(centerDot);
}
// 加载箭头
const savedElements = localStorage.getItem('savedElements');
if (savedElements) {
const elements = JSON.parse(savedElements);
elements.forEach(element => {
if (element.type === 'arrow') {
// Fix image path by adding 'images/' prefix if missing
if (!element.imagePath.startsWith('images/')) {
element.imagePath = `images/${element.imagePath}`;
}
addImageToContainer(element.imagePath, element, element.text);
}
});
console.log('[加载] 已加载元素:', elements);
}
}
// 阻止右键菜单冒泡
contextMenu.addEventListener('click', function(e) {
e.stopPropagation();
});
});