timeline and skill dragin improvments

This commit is contained in:
Akurosia Kamo 2026-05-23 21:03:13 +02:00
parent d0f54049e6
commit 3276e3bfb3
2 changed files with 70 additions and 2 deletions

View File

@ -723,6 +723,12 @@
background: var(--bg1);
max-width: 100%;
width: 100%;
cursor: grab;
user-select: none;
}
.timeline-scroll--dragging {
cursor: grabbing;
}
.timeline-grid {

View File

@ -1002,7 +1002,59 @@ function initTimeline(planId) {
const settings = document.getElementById('timeline-settings');
if (!timeline || !settings) return;
let timelinePan = null;
let suppressNextTimelineClick = false;
timeline.addEventListener('pointerdown', e => {
if (e.button !== 0) return;
if (!e.target.closest('.timeline-scroll')) return;
if (e.target.closest('.timeline-mitigation, .timeline-boss-action, .timeline-context-menu')) return;
const scroll = e.target.closest('.timeline-scroll');
timelinePan = {
scroll,
pointerId: e.pointerId,
startX: e.clientX,
startScrollLeft: scroll.scrollLeft,
moved: false,
};
scroll.setPointerCapture?.(e.pointerId);
});
timeline.addEventListener('pointermove', e => {
if (!timelinePan || timelinePan.pointerId !== e.pointerId) return;
const dx = e.clientX - timelinePan.startX;
if (Math.abs(dx) > 3) {
timelinePan.moved = true;
timelinePan.scroll.classList.add('timeline-scroll--dragging');
timelinePan.scroll.scrollLeft = timelinePan.startScrollLeft - dx;
e.preventDefault();
}
});
timeline.addEventListener('pointerup', e => {
if (!timelinePan || timelinePan.pointerId !== e.pointerId) return;
timelinePan.scroll.releasePointerCapture?.(e.pointerId);
timelinePan.scroll.classList.remove('timeline-scroll--dragging');
suppressNextTimelineClick = timelinePan.moved;
timelinePan = null;
if (suppressNextTimelineClick) setTimeout(() => { suppressNextTimelineClick = false; }, 0);
});
timeline.addEventListener('pointercancel', e => {
if (!timelinePan || timelinePan.pointerId !== e.pointerId) return;
timelinePan.scroll.releasePointerCapture?.(e.pointerId);
timelinePan.scroll.classList.remove('timeline-scroll--dragging');
timelinePan = null;
});
timeline.addEventListener('click', e => {
if (suppressNextTimelineClick) {
e.preventDefault();
e.stopPropagation();
suppressNextTimelineClick = false;
return;
}
closeTimelineMenu();
const boss = e.target.closest('.timeline-boss-action');
if (boss) {
@ -1063,11 +1115,20 @@ function initTimeline(planId) {
timeline.addEventListener('dragstart', e => {
const block = e.target.closest('.timeline-mitigation');
if (!block) return;
const plan = getPlan(planId);
const found = findTimelineAssignment(plan, {
mechanicId: block.dataset.mechanicId,
ability: block.dataset.ability,
job: block.dataset.job,
});
if (!plan || !found) return;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/plain', JSON.stringify({
mechanicId: block.dataset.mechanicId,
ability: block.dataset.ability,
job: block.dataset.job,
startClientX: e.clientX,
startTimestamp: assignmentStartMs(found.mechanic, found.assignment),
}));
});
@ -1086,8 +1147,9 @@ function initTimeline(planId) {
const plan = getPlan(planId);
if (!plan) return;
const rect = track.getBoundingClientRect();
const x = Math.max(0, Math.min(rect.width, e.clientX - rect.left));
const timestamp = (x / rect.width) * planDurationMs(plan);
const deltaPx = e.clientX - (Number(data.startClientX) || e.clientX);
const timestampDelta = (deltaPx / rect.width) * planDurationMs(plan);
const timestamp = (Number(data.startTimestamp) || 0) + timestampDelta;
if (row.dataset.ability && data.ability !== row.dataset.ability) return;
updateTimelineAssignmentPosition(planId, data.mechanicId, data.ability, data.job, row.dataset.job, timestamp);
});