Several days ago I asked the following question on webapps.stackexchange.com:
https://webapps.stackexchange.com/questions/54130/is-there-a-way-to-remove-overlaying-events-in-google-calendar
I didn't get any good answers so far, so I've decided to write my own little script that will change width of the event based on the number of overlapping events.
I want to avoid overlapping of the boxes and want them to stack.
Here's the initial test:
Below is a basic script with description:
$('[class^="tg-col"]').each(function(){ // each day column
//(Mon, Tue, etc. has class tg-col or tg-col-weekend.
var ItemArray = [];
$(this).find(".chip").each(function(){ //each event box has chip class.
var top = $$(this).position().top; //Get top pixels
var bottom = $$(this).height() + top; //get end of the event.
var arr = ItemArray.push({
class: $$(this).attr("class").split(" ")[0],
start : top,
end:bottom
});
});
var result = getOverlaps(ItemArray); //get overlaps counts number of overlapping events.
$$.each(result, function(index, value){
var ec = result[index].eventCount;
var w = 100/result[index].eventCount-1 + "%";
var el = $$("."+result[index].class);
el.width(w);
//el.css("left",w);
});
});
function getOverlaps(events) {
// sort events
events.sort(function (a, b) {
return a.start - b.start;
});
var results = [];
for (var i = 0, l = events.length; i < l; i++) {
var oEvent = events[i];
var nOverlaps = 0;
for (var j = 0; j < l; j++) {
var oCompareEvent = events[j];
if (oCompareEvent.start <= oEvent.end && oCompareEvent.end > oEvent.start || oCompareEvent.end <= oEvent.start && oCompareEvent.start > oEvent.end) {
nOverlaps++;
}
}
if (nOverlaps > 1) {
results.push({
class: oEvent.class,
eventCount: nOverlaps
});
}
}
return results;
}
This solution works only on simple events (on the left):
For more complex overlapping we cannot simply count numbers of overlaps and diving 100% / number of overlaps. We have to take into considerations other dimensions.
Also, after each manipulation in google calendar it redraws events and script changes are lost. Is there easier way to solve this problem?
(Maybe it is possible to modify js received from google directly? (But it's minified :().
jQuery position() Method The position() method returns the position (relative to its parent element) of the first matched element. This method returns an object with 2 properties; the top and left positions in pixels.
To get the X and Y coordinates for a div element with JavaScript, we an use the getBoundingXClientRect method. to select the div with querySelector . And then we call getBoundingClientRect to get the position of the div. Then we get the x and y coordinates of the div with position.
The offset() method set or returns the offset coordinates for the selected elements, relative to the document. When used to return the offset: This method returns the offset coordinates of the FIRST matched element. It returns an object with 2 properties; the top and left positions in pixels.
The position() method is an inbuilt method in jQuery which is used to find the position of the first matched element relative to its parent element in the DOM tree. Parameters: This method does not contains any parameters. Return Value: This method returns the position of the first matched element.
You already have correct left positions so you only need to set correct width.
In pseudocode:
foreach chip
chips_siblings = this.parent
.allchilds(chip)
.filter(this.top <= child.top <= this.bottom
&& child.left > this.left)
this.width = min(chips_siblings.left) - this.left
In JavaScript:
function placeChipsCorrectly() {
"use strict"
Array.prototype.forEach.call(
document.getElementsByClassName('chip'),
function(self) {
var siblings = Array.prototype.filter.call(
self.parentElement.getElementsByClassName('chip'),
function(child) {
return child.offsetTop >= self.offsetTop-2 &&
child.offsetTop <= self.offsetTop+self.offsetHeight-3 &&
child.offsetLeft > self.offsetLeft;
});
if (siblings.length > 0) {
var minLeft = Math.min.apply(null, Array.prototype.map.call(
siblings,
function(el) {
return el.offsetLeft;
}));
self.style.width = (minLeft - self.offsetLeft - 2) + "px";
}
});
}
placeChipsCorrectly();
As for tracking modification events:
After each data change you can see "Loading..." in the top right corner. After inspecting how it works you can see that it changes style
attribute of the container with id lo-c
.
So you can track it appearance and disappearance as following:
(new MutationObserver(placeChipsCorrectly)).observe(document.getElementById('lo-c'),{attributes: true});
When you only modify view and not data (e.g. by choosing another day or week) then "Loading..." doesn't appear. For these events you may track global click
event:
document.body.addEventListener('click', placeChipsCorrectly);
Keep in mind that both methods would take some overhead. If you would like to improve them, start by modifying the observer so that it calls placeChipsCorrectly
only on disappearance and by limiting click tracking to specific controls.
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