Compute left positioning in jquery div

A few days ago I asked the following question at webapps.stackexchange.com:
https://webapps.stackexchange.com/questions/54130/is-there-a-way-to-remove-overlaying-events-in-google-calendar

I have not received any good answers yet, so I decided to write my own little script that will change the width of the event based on the number of overlapping events.

I want to avoid overlapping boxes and want them to flow.

Here's the initial test:

enter image description here

Below is a basic script with a 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 only works on simple events (left):
enter image description here

For a more complex overlap, we cannot just calculate the number of overlaps and diving 100% / number of overlaps. We must consider other dimensions.

In addition, after each manipulation in the Google calendar, he redraws events and script changes are lost. Is there an easier way to solve this problem?
(Maybe you can change the js received from google directly? (But this is minified :().

+7
jquery html css google-calendar
source share
3 answers

You already have the right left positions, so you only need to set the correct width.

In pseudo code:

 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(); 

Regarding change tracking events:

After each data change, you can see "Loading ..." in the upper right corner. After checking how this works, you can see that it changes the style attribute of the container with id lo-c .
Thus, you can track its appearance and disappearance as follows:

 (new MutationObserver(placeChipsCorrectly)).observe(document.getElementById('lo-c'),{attributes: true}); 

When you only change the view, and not the data (for example, by selecting another day or week), then "Loading ..." does not appear. For these events, you can track the global click event:

 document.body.addEventListener('click', placeChipsCorrectly); 

Keep in mind that both methods will require some overhead. If you want to improve them, start by modifying the observer so that it placeChipsCorrectly only when it disappears and restricting click tracking to specific controls.

+3
source share

You can use the bounding box of your elements and try to avoid overlapping with (in pure javascript)

 document.getElementById("elemID").getBoundingClientRect(); 

I think the equivalent in jquery is like

 elemID.offset() 

In this case, you can have all the properties Top, Bottom, Right and Left. With it, you can more easily detect if you overlap or not. And as soon as you discover, just make adjustments from the borders of the overlapping frame.

0
source share

I think you should approach the problem from a different angle. You have a list of events with a start time and an end time. I believe that Google Calendar displays events with an accuracy of 15 minutes on the grid. In addition, note that we do not need to know how many events any event conflicts with it over the entire time, but instead how many events it conflicts with each interval.

So ... what if you do some preprocessing and determine how many events there are every 15 minute intervals. First you create an array:

 var timespans = Array(); //24*4 quarters for( var i = 0; i < 96; i++ ) { timespans[i] = 0; } 

Then we fill this day:

 for( var i = 0, l = events.length; i < l; i++) { var oEvent = events[i]; //Assuming that .start and .end is 'minutes since midnight' var firstQuarter = Math.floor( oEvent.start / 15 ); var lastQuarter = Math.ceil( oEvent.end / 15 ); for( var j = firstQuarter; j < lastQuarter; j++ ) { timespans[j] += 1; } } 

Then, if we go through all the events again, we just need to check the prepared array.

 for( var i = 0, l = events.length; i < l; i++) { var oEvent = events[i]; //Assuming that .start and .end is 'minutes since midnight' var firstQuarter = Math.floor( oEvent.start / 15 ); var lastQuarter = Math.ceil( oEvent.end / 15 ); var conflictingTimespans = timespans.slice( firstQuarter, lastQuarter ); //http://stackoverflow.com/a/1669222/2209007 var maxConflicting = Math.max.apply( null, conflictingTimespans ); //Set width of said element to columnWidth / maxConflicting } 

In addition, it should get rid of your problem, you will check for 2n events instead of n^2 events, which should improve performance.

As for your second question, I'm not sure how to help you with this.

0
source share

All Articles