日历日期排序:职业概述
Calendar date ordering: Occupation overview
我正在开发一个日历插件,可以按如下顺序显示我的职业概览:
现在我在日历上得到了 moment.js 的事件,所以它们的格式如下(按开始日期排序):
let events = [{
name: 'Event A',
start: '01-11-2021 00:00',
end: '08-11-2021 00:00',
},{
name: 'Event C',
start: '03-11-2021 00:00',
end: '06-11-2021 00:00',
},{
name: 'Event E',
start: '05-11-2021 00:00',
end: '08-11-2021 00:00',
},{
name: 'Event D',
start: '07-11-2021 00:00',
end: '12-11-2021 00:00',
},{
name: 'Event B',
start: '10-11-2021 00:00',
end: '17-11-2021 00:00',
},]
预期的 occupationOverview 数组类似于:
let ooArray = [
{ // Longest/bottom bar
start: '01-11-2021 00:00',
end: '17-11-2021 00:00',
group: 1
},
{ // Middle bar 1
start: '03-11-2021 00:00',
end: '08-11-2021 00:00',
group: 2
},
{ // Middle bar 2
start: '10-11-2021 00:00',
end: '12-11-2021 00:00',
group: 2
},
{ // Top bar 1
start: '05-11-2021 00:00',
end: '06-11-2021 00:00',
group: 3
},
{ // Top bar 2
start: '07-11-2021 00:00',
end: '08-11-2021 00:00',
group: 3
},]
老实说,我不知道如何对日历事件进行分组,因此它们会返回一个包含开始时间和结束时间的数组,如红框所示。
有人可以帮我解决这个问题吗?
谢谢!
看来您需要以毫秒为单位获取 diff
,并从大到小排序。您必须尝试使用它来查看它的排序方式(可能需要翻转 diff
语句中的 'a' 和 'b',因为我没有 运行它反对你的阵列)
const sortedArray = array.sort((a, b) => a.diff(b))
根据更新后的问题,对所有保留开始和结束属性的日期进行排序。按顺序处理它们,以便第一个日期(必须是开始)开始级别 1,即单人预订。
如果下一个日期结束,则该栏结束。但是,如果下一个日期开始,则会增加级别(即重复预订)。以下是一个实现,您可能希望按级别或开始日期对条形进行排序。
下面的函数首先获取所有日期按类型(开始或结束)升序排序。然后它处理每个日期 - 开始日期创建一个新的 bar,结束日期结束最近的 bar。结束时,最后一个 bar 从 starts 弹出并添加到 bars,这是一个数组成品吧。
这取决于源数据是否有效,即它必须以开始和结束结束,它们必须以正确的顺序且数量相等。
一个改进是确保开始和结束日期相同,开始总是在结束之前排序,因此零长度事件(里程碑?)不会按结束-开始顺序排列,这会导致在增加之前要减少的级别。开始和结束日期时间相同可能还有其他问题,请测试。
// Parse date in D-M-Y H:m format
function parseDMY(s) {
let [D, M, Y, H, m] = s.split(/\D/);
return new Date(Y, M - 1, D, H, m);
}
// Format as DD-MM-YYYY HH:mm
function formatDate(d) {
let z = n => ('0'+n).slice(-2);
return `${z(d.getDate())}-${z(d.getMonth()+1)}-${d.getFullYear()} ` +
`${z(d.getHours())}:${z(d.getMinutes())}`;
}
// Generates "occupation" bars
function calcBookingLevels(events) {
// Get sorted array of [{type, Date}]
let dates = events.reduce( (dates, event) => {
dates.push({type: 'start', date: parseDMY(event.start)},
{type: 'end', date: parseDMY(event.end)});
return dates;
}, []).sort((a, b) => a.date - b.date);
// Process dates to get occupation bars with levels
let bars = [];
let starts = [];
let level = 0;
dates.forEach(date => {
// If it's a start, start a new bar
if (date.type == 'start') {
let bar = {level: ++level, start: formatDate(date.date)};
starts.push(bar);
// Otherwise it's an end, close the most recent bar and
// move to bars array
} else {
let t = starts.pop();
t.end = formatDate(date.date);
--level;
bars.push(t);
}
})
return bars;
}
// Sample data
let events = [{
name: 'Event A',
start: '01-11-2021 00:00',
end: '08-11-2021 00:00',
},{
name: 'Event C',
start: '03-11-2021 00:00',
end: '06-11-2021 00:00',
},{
name: 'Event E',
start: '05-11-2021 00:00',
end: '08-11-2021 00:00',
},{
name: 'Event D',
start: '07-11-2021 00:00',
end: '12-11-2021 00:00',
},{
name: 'Event B',
start: '10-11-2021 00:00',
end: '17-11-2021 00:00',
},];
// Run it...
console.log(calcBookingLevels(events));
如果日期采用 YYYY-MM-DD HH:mm 格式,则可以将它们排序为字符串而不转换为日期。
在@RobG 的帮助下,我弄明白了。这是我对感兴趣的人的回答:
// Not needed for answer, but result gave warnings so yeah
moment.suppressDeprecationWarnings = true;
let newItems = []
let dateArray = []
let events = [{
name: 'Event A',
start: '01-11-2021 00:00',
end: '08-11-2021 00:00',
},{
name: 'Event C',
start: '03-11-2021 00:00',
end: '06-11-2021 00:00',
},{
name: 'Event E',
start: '05-11-2021 00:00',
end: '08-11-2021 00:00',
},{
name: 'Event D',
start: '07-11-2021 00:00',
end: '12-11-2021 00:00',
},{
name: 'Event B',
start: '10-11-2021 00:00',
end: '17-11-2021 00:00',
},]
// Make one big array with all start and end dates
events.forEach(event=> {
dateArray.push({
type: 'start',
date: event.start
}, {
type: 'end',
date: event.end
})
})
// Sort the dates from first to last
dateArray = dateArray.sort((left, right) => {
return moment(left.date).diff(moment(right.date))
})
let groupID = -1
// Loop through the array with all dates and add them to a group
// based on if the current date is a start or end
for (let i = 0; i < dateArray.length; i++) {
if (dateArray[i].type === 'start') groupID++
else groupID--
for (let ii = 0; ii <= groupID; ii++) {
if (dateArray[i + 1] &&
!moment(dateArray[i].date).isSame(dateArray[i + 1].date)) {
newItems.push({
group: 1,
start: dateArray[i].date,
end: dateArray[i + 1].date,
subgroup: 'sg_' + ii,
subgroupOrder: ii
})
}
}
}
console.log(newItems)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
我正在开发一个日历插件,可以按如下顺序显示我的职业概览:
现在我在日历上得到了 moment.js 的事件,所以它们的格式如下(按开始日期排序):
let events = [{
name: 'Event A',
start: '01-11-2021 00:00',
end: '08-11-2021 00:00',
},{
name: 'Event C',
start: '03-11-2021 00:00',
end: '06-11-2021 00:00',
},{
name: 'Event E',
start: '05-11-2021 00:00',
end: '08-11-2021 00:00',
},{
name: 'Event D',
start: '07-11-2021 00:00',
end: '12-11-2021 00:00',
},{
name: 'Event B',
start: '10-11-2021 00:00',
end: '17-11-2021 00:00',
},]
预期的 occupationOverview 数组类似于:
let ooArray = [
{ // Longest/bottom bar
start: '01-11-2021 00:00',
end: '17-11-2021 00:00',
group: 1
},
{ // Middle bar 1
start: '03-11-2021 00:00',
end: '08-11-2021 00:00',
group: 2
},
{ // Middle bar 2
start: '10-11-2021 00:00',
end: '12-11-2021 00:00',
group: 2
},
{ // Top bar 1
start: '05-11-2021 00:00',
end: '06-11-2021 00:00',
group: 3
},
{ // Top bar 2
start: '07-11-2021 00:00',
end: '08-11-2021 00:00',
group: 3
},]
老实说,我不知道如何对日历事件进行分组,因此它们会返回一个包含开始时间和结束时间的数组,如红框所示。
有人可以帮我解决这个问题吗? 谢谢!
看来您需要以毫秒为单位获取 diff
,并从大到小排序。您必须尝试使用它来查看它的排序方式(可能需要翻转 diff
语句中的 'a' 和 'b',因为我没有 运行它反对你的阵列)
const sortedArray = array.sort((a, b) => a.diff(b))
根据更新后的问题,对所有保留开始和结束属性的日期进行排序。按顺序处理它们,以便第一个日期(必须是开始)开始级别 1,即单人预订。
如果下一个日期结束,则该栏结束。但是,如果下一个日期开始,则会增加级别(即重复预订)。以下是一个实现,您可能希望按级别或开始日期对条形进行排序。
下面的函数首先获取所有日期按类型(开始或结束)升序排序。然后它处理每个日期 - 开始日期创建一个新的 bar,结束日期结束最近的 bar。结束时,最后一个 bar 从 starts 弹出并添加到 bars,这是一个数组成品吧。
这取决于源数据是否有效,即它必须以开始和结束结束,它们必须以正确的顺序且数量相等。
一个改进是确保开始和结束日期相同,开始总是在结束之前排序,因此零长度事件(里程碑?)不会按结束-开始顺序排列,这会导致在增加之前要减少的级别。开始和结束日期时间相同可能还有其他问题,请测试。
// Parse date in D-M-Y H:m format
function parseDMY(s) {
let [D, M, Y, H, m] = s.split(/\D/);
return new Date(Y, M - 1, D, H, m);
}
// Format as DD-MM-YYYY HH:mm
function formatDate(d) {
let z = n => ('0'+n).slice(-2);
return `${z(d.getDate())}-${z(d.getMonth()+1)}-${d.getFullYear()} ` +
`${z(d.getHours())}:${z(d.getMinutes())}`;
}
// Generates "occupation" bars
function calcBookingLevels(events) {
// Get sorted array of [{type, Date}]
let dates = events.reduce( (dates, event) => {
dates.push({type: 'start', date: parseDMY(event.start)},
{type: 'end', date: parseDMY(event.end)});
return dates;
}, []).sort((a, b) => a.date - b.date);
// Process dates to get occupation bars with levels
let bars = [];
let starts = [];
let level = 0;
dates.forEach(date => {
// If it's a start, start a new bar
if (date.type == 'start') {
let bar = {level: ++level, start: formatDate(date.date)};
starts.push(bar);
// Otherwise it's an end, close the most recent bar and
// move to bars array
} else {
let t = starts.pop();
t.end = formatDate(date.date);
--level;
bars.push(t);
}
})
return bars;
}
// Sample data
let events = [{
name: 'Event A',
start: '01-11-2021 00:00',
end: '08-11-2021 00:00',
},{
name: 'Event C',
start: '03-11-2021 00:00',
end: '06-11-2021 00:00',
},{
name: 'Event E',
start: '05-11-2021 00:00',
end: '08-11-2021 00:00',
},{
name: 'Event D',
start: '07-11-2021 00:00',
end: '12-11-2021 00:00',
},{
name: 'Event B',
start: '10-11-2021 00:00',
end: '17-11-2021 00:00',
},];
// Run it...
console.log(calcBookingLevels(events));
如果日期采用 YYYY-MM-DD HH:mm 格式,则可以将它们排序为字符串而不转换为日期。
在@RobG 的帮助下,我弄明白了。这是我对感兴趣的人的回答:
// Not needed for answer, but result gave warnings so yeah
moment.suppressDeprecationWarnings = true;
let newItems = []
let dateArray = []
let events = [{
name: 'Event A',
start: '01-11-2021 00:00',
end: '08-11-2021 00:00',
},{
name: 'Event C',
start: '03-11-2021 00:00',
end: '06-11-2021 00:00',
},{
name: 'Event E',
start: '05-11-2021 00:00',
end: '08-11-2021 00:00',
},{
name: 'Event D',
start: '07-11-2021 00:00',
end: '12-11-2021 00:00',
},{
name: 'Event B',
start: '10-11-2021 00:00',
end: '17-11-2021 00:00',
},]
// Make one big array with all start and end dates
events.forEach(event=> {
dateArray.push({
type: 'start',
date: event.start
}, {
type: 'end',
date: event.end
})
})
// Sort the dates from first to last
dateArray = dateArray.sort((left, right) => {
return moment(left.date).diff(moment(right.date))
})
let groupID = -1
// Loop through the array with all dates and add them to a group
// based on if the current date is a start or end
for (let i = 0; i < dateArray.length; i++) {
if (dateArray[i].type === 'start') groupID++
else groupID--
for (let ii = 0; ii <= groupID; ii++) {
if (dateArray[i + 1] &&
!moment(dateArray[i].date).isSame(dateArray[i + 1].date)) {
newItems.push({
group: 1,
start: dateArray[i].date,
end: dateArray[i + 1].date,
subgroup: 'sg_' + ii,
subgroupOrder: ii
})
}
}
}
console.log(newItems)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>