Added timeline editor improvements

This commit is contained in:
mxdanger 2022-05-09 18:03:20 -07:00
parent 5ddec7631b
commit 275ac22684
3 changed files with 131 additions and 24 deletions

View file

@ -243,7 +243,7 @@ #bottomBar {
padding-bottom: max(0.5rem, env(safe-area-inset-bottom)) !important;
}
#bottomBar:hover {
#bottomBar:hover, #bottomBar:focus-within {
z-index: 1;
}
@ -440,8 +440,8 @@ #periods #periodsStatus:empty {
}
.period-group.no-time-slider input,
.period-group.no-time-slider label {
display: none;
.period-group.no-time-slider .period-input-controls {
display: none !important;
}
/* purgecss end ignore */

View file

@ -156,14 +156,17 @@ function initDraw() {
}
})
window.addEventListener("mousemove", function (e) {
container.addEventListener("mousemove", function (e) {
if (!dragging && drawing && path.length > 0) {
const coords = getCanvasCoords(e.clientX, e.clientY)
render([...path, coords])
}
})
container.addEventListener("mouseout", function () {
if (!dragging && drawing && path.length > 0) {
render(path)
}
})
window.addEventListener("keyup", function (e) {
@ -785,57 +788,147 @@ function initPeriodGroups() {
periodGroups.replaceChildren()
pathWithPeriods.forEach(([period, path], index) => {
// Set element variables
const periodGroupEl = periodGroupTemplate.cloneNode(true)
periodGroupEl.id = "periodGroup" + index
const startPeriodEl = periodGroupEl.querySelector('.period-start')
const startPeriodListEl = periodGroupEl.querySelector('#periodStartList')
const startPeriodLabelEl = startPeriodEl.previousElementSibling.querySelector('label')
const startPeriodLeftEl = periodGroupEl.querySelector('#periodStartLeft')
const startPeriodRightEl = periodGroupEl.querySelector('#periodStartRight')
const startPeriodViewEl = periodGroupEl.querySelector('#periodStartView')
const endPeriodEl = periodGroupEl.querySelector('.period-end')
const endPeriodListEl = periodGroupEl.querySelector('#periodEndList')
const periodDeleteEl = periodGroupEl.querySelector('.period-delete')
const periodDuplicateEl = periodGroupEl.querySelector('.period-duplicate')
const periodVariationEl = periodGroupEl.querySelector('.period-variation')
const endPeriodLabelEl = endPeriodEl.previousElementSibling.querySelector('label')
const endPeriodLeftEl = periodGroupEl.querySelector('#periodEndLeft')
const endPeriodRightEl = periodGroupEl.querySelector('#periodEndRight')
const endPeriodViewEl = periodGroupEl.querySelector('#periodEndView')
const periodCopyEl = periodGroupEl.querySelector('.period-copy')
const periodDuplicateEl = periodGroupEl.querySelector('.period-duplicate')
const periodDeleteEl = periodGroupEl.querySelector('.period-delete')
const periodVariationEl = periodGroupEl.querySelector('.period-variation')
const periodStatusEl = periodGroupEl.querySelector('.period-status')
const [start, end, variation] = parsePeriod(period)
// Set index
startPeriodEl.id = "periodStart" + index
startPeriodEl.previousElementSibling.htmlFor = startPeriodEl.id
startPeriodListEl.id = "periodStartList" + index
startPeriodLabelEl.htmlFor = startPeriodEl.id
startPeriodListEl.id += index
startPeriodEl.setAttribute("list", startPeriodListEl.id)
startPeriodLeftEl.id += index
startPeriodRightEl.id += index
startPeriodViewEl.id += index
endPeriodEl.id = "periodEnd" + index
endPeriodEl.previousElementSibling.htmlFor = endPeriodEl.id
endPeriodListEl.id = "periodEndList" + index
endPeriodLabelEl.htmlFor = endPeriodEl.id
endPeriodListEl.id += index
endPeriodEl.setAttribute("list", endPeriodListEl.id)
periodVariationEl.id = "periodVariation" + index
endPeriodLeftEl.id += index
endPeriodRightEl.id += index
endPeriodViewEl.id += index
periodCopyEl.id = "periodCopy" + index
periodVariationEl.id = "periodVariation" + index
periodStatusEl.id = "periodStatus" + index
// Set ranges
startPeriodEl.min = variationsConfig[variation].drawablePeriods[0]
endPeriodEl.min = variationsConfig[variation].drawablePeriods[0]
startPeriodEl.max = variationsConfig[variation].drawablePeriods[1]
endPeriodEl.max = variationsConfig[variation].drawablePeriods[1]
startPeriodEl.value = start
endPeriodEl.value = end
// Adds tick marks to assit in preventing overlap
startPeriodListEl.innerHTML = '<option value="' + (end - 1) + '"></option>'
endPeriodListEl.innerHTML = '<option value="' + (start + 1) + '"></option>'
// Removes slider controls if no timeline range exists
if (startPeriodEl.max == 0) periodGroupEl.classList.add('no-time-slider')
else periodGroupEl.classList.remove('no-time-slider')
// If one period disable delete
if (pathWithPeriods.length === 1) periodDeleteEl.disabled = true
startPeriodEl.addEventListener('input', event => {
endPeriodListEl.innerHTML = '<option value="' + (parseInt(event.target.value) + 1) + '"></option>'
timelineSlider.value = parseInt(event.target.value)
updateTime(parseInt(event.target.value), variation)
startPeriodEl.addEventListener('input', e => startPeriodUpdate(e.target.value))
startPeriodLeftEl.addEventListener('click', () => {
startPeriodEl.value = parseInt(startPeriodEl.value) - 1
startPeriodUpdate(startPeriodEl.value)
})
endPeriodEl.addEventListener('input', event => {
startPeriodListEl.innerHTML = '<option value="' + (parseInt(event.target.value) - 1) + '"></option>'
timelineSlider.value = parseInt(event.target.value)
updateTime(parseInt(event.target.value), variation)
startPeriodRightEl.addEventListener('click', () => {
startPeriodEl.value = parseInt(startPeriodEl.value) + 1
startPeriodUpdate(startPeriodEl.value)
})
startPeriodViewEl.addEventListener('click', () => {
updateTime(parseInt(startPeriodEl.value), variation)
// Set zoom view
let activeCenter = calculateCenter(pathWithPeriods[index][1])
zoomOrigin = [innerContainer.clientWidth / 2 - activeCenter[0] * zoom, innerContainer.clientHeight / 2 - activeCenter[1] * zoom]
scaleZoomOrigin = [2000 / 2 - activeCenter[0], 2000 / 2 - activeCenter[1]]
applyView()
})
function startPeriodUpdate(value) {
endPeriodListEl.innerHTML = '<option value="' + (parseInt(value) + 1) + '"></option>'
timelineSlider.value = parseInt(value)
updateTime(parseInt(value), variation)
// Set disabled states
if (startPeriodEl.value == startPeriodEl.min) {
startPeriodLeftEl.disabled = true
startPeriodRightEl.disabled = false
} else if (startPeriodEl.value == startPeriodEl.max) {
startPeriodLeftEl.disabled = false
startPeriodRightEl.disabled = true
} else {
startPeriodLeftEl.disabled = false
startPeriodRightEl.disabled = false
}
}
endPeriodEl.addEventListener('input', e => endPeriodUpdate(e.target.value))
endPeriodLeftEl.addEventListener('click', () => {
endPeriodEl.value = parseInt(endPeriodEl.value) - 1
endPeriodUpdate(endPeriodEl.value)
})
endPeriodRightEl.addEventListener('click', () => {
endPeriodEl.value = parseInt(endPeriodEl.value) + 1
endPeriodUpdate(endPeriodEl.value)
})
endPeriodViewEl.addEventListener('click', () => {
updateTime(parseInt(endPeriodEl.value), variation)
// Set zoom view
let activeCenter = calculateCenter(pathWithPeriods[index][1])
zoomOrigin = [innerContainer.clientWidth / 2 - activeCenter[0] * zoom, innerContainer.clientHeight / 2 - activeCenter[1] * zoom]
scaleZoomOrigin = [2000 / 2 - activeCenter[0], 2000 / 2 - activeCenter[1]]
applyView()
})
function endPeriodUpdate(value) {
startPeriodListEl.innerHTML = '<option value="' + (parseInt(value) + 1) + '"></option>'
timelineSlider.value = parseInt(value)
updateTime(parseInt(value), variation)
// Set disabled states
if (endPeriodEl.value == endPeriodEl.min) {
endPeriodLeftEl.disabled = true
endPeriodRightEl.disabled = false
} else if (endPeriodEl.value == endPeriodEl.max) {
endPeriodLeftEl.disabled = false
endPeriodRightEl.disabled = true
} else {
endPeriodLeftEl.disabled = false
endPeriodRightEl.disabled = false
}
}
periodDeleteEl.addEventListener('click', () => {
if (pathWithPeriods.length === 1) return
pathWithPeriods.splice(index, 1)

View file

@ -409,10 +409,24 @@ <h5 class="modal-title" id="donateModalLabel">Donation Links</h5>
<div class="period-group card mb-2">
<div class="card-body">
<div class="period-status alert alert-danger small py-2" role="alert"></div>
<label for="period-start" class="form-label">Start Period</label>
<div class="period-input-controls d-flex align-items-center mb-2">
<label for="period-start">Start Period</label>
<div class="btn-group btn-group-sm ms-auto" role="group" aria-label="Start period controls">
<button type="button" class="btn btn-secondary" id="periodStartLeft" aria-label="Left"><i class="bi bi-caret-left-fill" aria-hidden="true"></i></button>
<button type="button" class="btn btn-secondary" id="periodStartRight" aria-label="Right"><i class="bi bi-caret-right-fill" aria-hidden="true"></i></button>
</div>
<button type="button" class="btn btn-secondary btn-sm ms-2" id="periodStartView">View</button>
</div>
<input type="range" class="period-start form-range" id="period-start" min="0" list="periodStartList">
<datalist id="periodStartList"></datalist>
<label for="period-end" class="form-label">End Period</label>
<div class="period-input-controls d-flex align-items-center mb-2">
<label for="period-end">End Period</label>
<div class="btn-group btn-group-sm ms-auto" role="group" aria-label="End period controls">
<button type="button" class="btn btn-secondary" id="periodEndLeft" aria-label="Left"><i class="bi bi-caret-left-fill" aria-hidden="true"></i></button>
<button type="button" class="btn btn-secondary" id="periodEndRight" aria-label="Right"><i class="bi bi-caret-right-fill" aria-hidden="true"></i></button>
</div>
<button type="button" class="btn btn-secondary btn-sm ms-2" id="periodEndView">View</button>
</div>
<input type="range" class="period-end form-range mb-2" id="period-end" min="0" list="periodEndList">
<datalist id="periodEndList"></datalist>
<div class="d-flex flex-wrap gap-2 mb-2">