Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate left positioning in div jquery

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:

enter image description here

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):
enter image description here

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 :().

like image 430
user194076 Avatar asked Jan 18 '14 08:01

user194076


People also ask

How to get left position of element in jQuery?

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.

How do you find XY coordinates of a div?

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.

What is offset()?

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.

What is at jQuery position?

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.


1 Answers

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.

like image 183
user Avatar answered Oct 13 '22 01:10

user