2014-01-18 16 views
7

前幾天我問上webapps.stackexchange.com以下問題:
https://webapps.stackexchange.com/questions/54130/is-there-a-way-to-remove-overlaying-events-in-google-calendar
計算留在格jQuery的定位

我沒有得到任何好到目前爲止的答案,所以我決定編寫我自己的小腳本,根據重疊事件的數量改變事件的寬度。

我想避免箱子重疊,並希望它們堆疊。

這裏的初始測試:

enter image description here

下面是說明一個基本的腳本:

$('[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; 
} 

此解決方案僅適用於簡單的事件(左側):
enter image description here

對於更復雜的重疊,我們不能簡單地計算重疊數量和潛水100%/重疊數量。我們必須考慮其他方面。

此外,在谷歌日曆中的每個操作後,它重繪事件和腳本更改都會丟失。有更簡單的方法來解決這個問題嗎?
(也許是可能的修改從谷歌直接?(收到的js但它精縮:()。

+4

如果有人想擺弄它,這裏是一個日曆小提琴[Here](http://jsfiddle.net/JfRU9/) – Olumide

+0

是否可以更改每個事件框的寬度和高度?如果沒有,是否可以更改容納這些事件框的每個容器的寬度和/或高度? –

+0

檢查Google日曆,我們只能更改每個事件的寬度和位置。對? –

回答

3

您已擁有正確的左側位置,因此您只需設置正確的寬度。

僞代碼:

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 

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

至於跟蹤修改事件:在頂部

後每一個數據改變,你可以看到 「正在加載...」右上角。在檢查它的工作方式後,可以看到它改變了容器的style屬性,其ID爲lo-c
所以,你可以跟蹤它的出現和消失如下:

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

當你只修改視圖,而不是數據(例如,通過選擇另一天或周)然後選擇「載入中...」沒有出現。對於這些事件,你可以跟蹤全球click事件:

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

請記住,這兩種方法將採取一些開銷。如果您想改進它們,請首先修改觀察者,使其僅在消失時調用placeChipsCorrectly,並將點擊跟蹤限制爲特定控件。

+0

非常感謝。它效果很好。有幾件事我想問你的建議。 1)當有兩個重疊事件時,它不能正確放置籌碼:一個是從下午5點到6點設置的,另一個是從5點到下午5點設置的。 2)addEventListeber不會改變行爲,一切都會重置。我應該使用DomAttrModified以外的東西嗎? – user194076

+0

另外,它不能正確計算寬度。有兩對和三個項目。 http://tinypic.com/r/s5bclz/5 – user194076

+0

@ user194076我已經更新了我的答案。 DOMAttrModified被跨瀏覽器MutationObserver取代。增加了更多像素調整功能,以便在您顯示的情況下正常工作。 – user

0

你可以使用你的元素的邊框,並嘗試使用,以避免重疊(在純JavaScript)

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

我認爲在jQuery的等效是一樣的東西

elemID.offset() 

有了這個,你可以擁有所有上,下,左,右屬性。有了它,你可以這樣更容易地檢測,如果你是重疊或不重疊如果你已經檢測到,只需從疊加框界限進行調整即可。

+0

'.offset()!= .getBoundingClientRect()' –

+0

感謝您的回答,我不確定如何將getBoundingClientRect應用於我的示例。我從getBoundingClientRect獲得的信息是不夠的。 – user194076

0

我認爲你應該從另一個角度來看問題。你有一個事件清單,包括開始時間和結束時間。我相信Google日曆會在網格上以15分鐘的精度顯示事件。此外,請注意,我們無需知道某個事件在整個時間段內與某個事件發生衝突的次數,而是需要知道在每個時間間隔內衝突的事件數量。

那麼...如果你做了一些準備工作,並確定每個15分鐘的時間範圍內有多少事件。首先需要準備一個數組:

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

然後我們填充這個日子:

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; 
    } 
} 

然後如果我們遍歷所有的事件再次,我們只需要檢查我們準備的數組。

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 
} 

除此之外,它應該擺脫你的問題,你將只檢查2n事件,而不是n^2事件,這應該提高性能。

至於你的第二個問題,我不確定如何幫助你。