几天前我在webapps.stackexchange.com上问了以下问题:
https://webapps.stackexchange.com/questions/54130/is-there-a-way-to-remove-overlaying-events-in-google-calendar
我想避免重叠这些框并希望它们堆叠。
这是初步测试:
以下是带有说明的基本脚本:
$('[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;
}
此解决方案仅适用于简单事件(左侧):
对于更复杂的重叠,我们不能简单地计算重叠次数和潜水100%/重叠次数。我们必须考虑其他方面。
此外,在Google日历中的每次操作之后,它都会重绘事件并且脚本更改会丢失。有没有更简单的方法来解决这个问题?
(也许可以直接修改从谷歌收到的js?(但它缩小了:()。
答案 0 :(得分: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
的容器的lo-c
属性。
所以你可以跟踪它的外观和消失如下:
(new MutationObserver(placeChipsCorrectly)).observe(document.getElementById('lo-c'),{attributes: true});
当您仅修改视图而不是数据时(例如,通过选择另一天或一周),则不会显示“正在加载...”。对于这些活动,您可以跟踪全球click
事件:
document.body.addEventListener('click', placeChipsCorrectly);
请记住,这两种方法都需要一些开销。如果您想要改进它们,请首先修改观察者,使其仅在消失时调用placeChipsCorrectly
,并将点击跟踪限制为特定控件。
答案 1 :(得分:0)
您可以使用元素的边界框并尝试使用(在纯JavaScript中)避免重叠
document.getElementById("elemID").getBoundingClientRect();
我认为jquery中的等价物就像
elemID.offset()
有了这个,你可以拥有所有的Top,Bottom,Right和Left属性。有了它,您可以更轻松地检测您是否重叠。一旦你检测到,只需从重叠的框边界进行调整。
答案 2 :(得分: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
事件,这应该会提高性能。
至于你的第二个问题,我不确定如何帮助你。