I'm creating an event scheduler in vanilla JS. I'm currently working on the ability to highlight a time-span by "dragging" the mouse over the desired times. I've got it working fairly well, but I want the rest of the day to highlight automatically if the user starts dragging on one day (e.g Monday) over to the next (e.g Tuesday).
In other words, if you start highlighting on Monday at 03 am and drag over to Tuesday 05 am, the highlighted area should automatically be Monday 03-07 and Tuesday 00-05.
I almost got it working, but all these coordinates and calculations makes me dizzy. Any help or guidance would be most welcome.
This is the snippet I'm having issues with:
if((j >= (startCol-1) && j <= (col-1) && i >= (startRow-1) && i < (row-1))) {
rows[i].children[j].classList.add('selected');
} else if((j > (startCol-1)) && (j <= (col-1)) && (i < (startRow-1))) {
rows[i].children[j].classList.add('selected');
} else if((j < (col-1) && (j >= (startCol-1)) && (i >= (row-1)))) {
rows[i].children[j].classList.add('selected');
} else {
rows[i].children[j].classList.remove('selected');
}
Here's a full snippet
const table = document.querySelector('.table');
const rows = document.querySelectorAll('.row');
const sqSize = 28;
let selValue = 'p1';
let didMouseMove = false;
let startRow;
let startCol;
const cb = (e) => {
didMouseMove = true;
const x = e.clientX - table.offsetLeft;
const y = e.clientY - table.offsetTop;
const row = Math.round(y / sqSize);
const col = Math.round(x / sqSize);
for(let i=0; i < rows.length; i++) {
for(let j=0; j < rows[i].children.length; j++) {
if((j >= (startCol-1) && j <= (col-1) && i >= (startRow-1) && i < (row-1))) {
rows[i].children[j].classList.add('selected');
} else if((j > (startCol-1)) && (j <= (col-1)) && (i < (startRow-1))) {
rows[i].children[j].classList.add('selected');
} else if((j < (col-1) && (j >= (startCol-1)) && (i >= (row-1)))) {
rows[i].children[j].classList.add('selected');
} else {
rows[i].children[j].classList.remove('selected');
}
}
}
}
table.addEventListener('mousedown', (e) => {
startRow = Math.round((e.clientY - table.offsetTop) / sqSize);
startCol = Math.round((e.clientX - table.offsetLeft) / sqSize);
table.addEventListener('mousemove', cb);
});
table.addEventListener('mouseup', (e) => {
const x = table.querySelectorAll('.selected');
for (let i = 0; i < x.length; i++) {
x[i].className = selValue;
}
if(!didMouseMove && !e.target.classList.contains('row')) {
e.target.classList.toggle(selValue);
}
didMouseMove = false;
table.removeEventListener('mousemove', cb);
});
document.getElementById('sel').addEventListener('change', (e) => {
selValue = e.target.value;
});
body {
margin: 0;
padding: 0;
}
.head {
font-size: 0;
margin-left: 32px;
}
.head > div {
font-size: 12px;
display: inline-block;
width: 25px;
margin: 0 2px;
text-align: center;
}
.pre {
display: inline-block;
font-size: 0;
vertical-align: top;
width: 32px;
margin-top: -8px;
}
.pre > div {
height: 25px;
margin: 2px 0;
font-size: 12px;
display: inline-block;
}
.table {
display: inline-block;
}
.wrapper {
display: inline-block;
position: relative;
}
.row {
font-size: 0;
}
.row > div {
display: inline-block;
border: 1px solid black;
margin: 1px;
width: 25px;
height: 25px;
}
.p1 {
background: green;
}
.p2 {
background: blue;
}
.p3 {
background: orange;
}
.selected {
background: grey;
}
<div>
<select id="sel">
<option value="p1">Profile 1</option>
<option value="p2">Profile 2</option>
<option value="p3">Profile 3</option>
</select>
</div>
<div class='wrapper'>
<div class='head'>
<div>Mon</div>
<div>Tue</div>
<div>Wed</div>
<div>Thu</div>
<div>Fri</div>
<div>Sat</div>
<div>Sun</div>
</div>
<div>
<div class='pre'>
<div>00:00</div>
<div>00:30</div>
<div>01:00</div>
<div>01:30</div>
<div>02:00</div>
<div>02:30</div>
<div>03:00</div>
<div>03:30</div>
<div>04:00</div>
<div>04:30</div>
<div>05:00</div>
<div>05:30</div>
<div>06:00</div>
<div>06:30</div>
<div>07:00</div>
</div>
<div class='table'>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class='row'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</div>
</div>
and jsfiddle fork: http://jsfiddle.net/a2v9rd50/1/
I wrote this, that needs to be tweaked and refactored, but the selection "works".
I dynamically generated an ugly a stylished calendar. Each cell has an id built like this : day_halfhour
. day
being the x coordinate, halfhour
being the y one. The cell for monday at 00:00 has id 0_0
. Sunday 23:30 has 6_47
.
There's 2 events listener on each cell.
One for selection starting (mousedown
) that sets up the starting coordinates (day + hour) startPoint
and raises the flag selecting
The other one is used for the selection (mouseover
). It's executed only when the flag selecting
is true. It sets the ending coordinate (day + hour) coor
with the current cell id (x_y
)
There's a 3rd event, on document (mouseup
) that displays in console the starting and ending coordinates.
It's up to you to use that final event to design the selected dates and manage datas.
function changeColor(x, y, state)
{
let cell = document.getElementById(x + '_' + y);
if (cell)
cell.className = state;
}
let tbl = document.createElement('table');
let container = document.getElementById('myTable');
let startPoint = null;
let endPoint = null;
let selecting = false;
for (let i = 0; i < 48; ++i)
{
let tr = document.createElement('tr');
for (let j = 0; j < 7; ++j)
{
let td = document.createElement('td');
td.setAttribute('id', j + "_" + i);
td.innerHTML = "A";
td.addEventListener('mousedown', (e) =>
{
let coortemp = e.srcElement.id.split('_');
startPoint = [coortemp[0], coortemp[1]];
selecting = true;
changeColor(coortemp[0], coortemp[1], "selecting");
});
td.addEventListener('mouseover', (e) =>
{
if (selecting)
{
endPoint = e.srcElement.id.split('_');
for (let x = 0; x < 7; ++x)
{
for (let y = 0; y < 48; ++y)
{
//We're out of range concerning selection. background is white
if (x < startPoint[0]
|| x > endPoint[0])
changeColor(x, y, "deselected");
else
{
//In the case where we're "painting" the first day
//of the selection.
if (x == startPoint[0])
{
/*
* This checks if start and end are the same day.
* to avoid "painting" too much hours
* Or if days are differents, so we can "paint" until midnight
*/
if (y >= startPoint[1]
&& ((startPoint[0] == endPoint[0]
&& y <= endPoint[1])
|| startPoint[0] != endPoint[0]))
{
changeColor(x, y, "selecting");
}
else
{
changeColor(x, y, "deselected");
}
}
//last day of selection ...
else if (x == endPoint[0])
{
//... before or at last hour
if (y <= endPoint[1])
{
changeColor(x, y, "selecting");
}
else
{
changeColor(x, y, "deselected");
}
}
//There, we're definitely in range and we can blindly "paint"
else
{
changeColor(x, y, "selecting");
}
}
}
}
}
});
tr.appendChild(td);
}
tbl.appendChild(tr);
}
container.appendChild(tbl);
document.addEventListener('mouseup', () =>
{
if (selecting)
{
if (!endPoint)
endPoint = startPoint;
console.log('final selection : from day ' + startPoint[0] + ' half-hour * ' + startPoint[1] + ' to day ' + endPoint[0] + ' half-hour * ' + endPoint[1]);
selecting = false;
let days = document.getElementsByClassName("selecting");
while (days.length)
days[0].className = "selected";
}
});
.selecting
{
background-color: #A9A9A9;
}
.deselected
{
background-color: #FFFFFF;
}
.selected
{
background-color: #00FF00;
}
<div id="myTable">
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With