From f935d337d6067089ffaaede29b3f317c54621828 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 2 Oct 2023 23:42:08 +0100 Subject: [PATCH] Added collision avoidance and marker methods --- bbtimeline.css | 0 bbtimeline.js | 491 ++++++++++++++++++++++++++++++++++--------------- demo-test.html | 79 ++++++-- 3 files changed, 412 insertions(+), 158 deletions(-) delete mode 100644 bbtimeline.css diff --git a/bbtimeline.css b/bbtimeline.css deleted file mode 100644 index e69de29..0000000 diff --git a/bbtimeline.js b/bbtimeline.js index 4cb6935..16ddd51 100644 --- a/bbtimeline.js +++ b/bbtimeline.js @@ -36,16 +36,21 @@ class BBTimeline { BorderColour: "#3A5D9C", BorderWidth: 2, BackColour: "#D4DEEF", - Width: 10 + Width: 10, + ForeColour: "#3A5D9C", + Font: "9pt Arial", + LabelCollisionMargin: 4 }; a.HighlightLine = { Colour: "#A6A6A6", Width: 1, }; a.Events = []; - a.StartDate = new Date(); - a.ClientRectangle = a.getClientRectangle(); + a.StartDate = a.DateToString(new Date(), "yyyy-MM-dd"); + a.ShowDate = a.StartDate; + a.GraphRectangle = a.calcGraphArea(); a.Enabled = false; + a.Debug = false; a.ctx = a.Container.getContext("2d"); a.ctx.canvas.width = a.Size.Width; @@ -54,32 +59,50 @@ class BBTimeline { a.initialiseComponents(); } - Load(startDate) { + AddEvent(date, label, options) { const a = this; - a.StartDate = ((typeof(startDate) == "undefined") ? new Date() : startDate); + const _options = Object.assign(a.GetEventItem(), options); - a.invalidate(true); + let event = a.FindEvent(date); + if (event == null) { + a.Events.push(a.GetEvent(date)); - a.Enabled = true; + event = a.FindEvent(date); + } + + if (label != null) { + event.Label = label; + } + + event.Events.push(_options); } - Clear(all) { + Clear() { const a = this; - if (all) { - a.ctx.clearRect(0, 0, a.ctx.canvas.width, a.ctx.canvas.height); + a.ctx.clearRect(0, 0, a.ctx.canvas.width, a.ctx.canvas.height); - a.Events = []; - a.Enabled = false; - } else { - const rect = a.getClientCoords(); + a.StartDate = a.DateToString(new Date(), "yyyy-MM-dd"); + a.ShowDate = a.StartDate; + a.Enabled = false; + a.Events = []; + } - a.ctx.clearRect((rect.X1 + a.Axis.LineWidth), rect.Y1, (rect.X2 - rect.X1 - a.Axis.LineWidth), (rect.Y2 - rect.Y1 - a.Axis.LineWidth)); + DeleteMarker(date) + { + const a = this; + + for (let i=0; i= e.X1) && (x <= e.X2) && (y >= e.Y1) && (y <= e.Y2)){ return a.Events[i]; @@ -106,77 +164,265 @@ class BBTimeline { return null; } - AddEvent(date, title, description, link) { + Load(startDate) { const a = this; - a.Events.push({ - Date: date, - Title: title, - Description: description, - Link: link - }); + a.StartDate = startDate; - a.invalidate(false); + a.Show(startDate); } + Show(date) { + const a = this; + + if (a.stringToDate(date) < a.stringToDate(a.StartDate)) { + date = a.StartDate; + } + + a.ShowDate = date; + a.Enabled = true; + + a.Invalidate(true, true); + } + + ShowNext() { + const a = this; + + let date = a.stringToDate(a.ShowDate); + date.setMonth(date.getMonth() + 1); + + a.Show(a.DateToString(date, "yyyy-MM-dd")); + } + + ShowPrevious() { + const a = this; + + let date = a.stringToDate(a.ShowDate); + date.setMonth(date.getMonth() - 1); + + a.Show(a.DateToString(date, "yyyy-MM-dd")); + } + + UpdateLabel(date, label) { + const a = this; + + let event = a.FindEvent(date); + if (event == null) { + return; + } + + event.Label = label; + + a.Invalidate(false, true); + } + + UpdateMarker(date, borderColour, backColour) { + const a = this; + + let event = a.FindEvent(date); + if (event == null) { + return; + } + + event.BorderColour = borderColour; + event.BackColour = backColour; + + a.Invalidate(false, true); + } initialiseComponents() { const a = this; const coords = a.getClientCoords(); - // Vertical highlight line - // a.ctx.canvas.addEventListener('mousemove', function (e) { - // if (!a.Enabled) { - // return; - // } - - // a.invalidate(false); - - // if ((e.offsetX > (coords.X1 + a.Axis.LineWidth)) && (e.offsetX < coords.X2) && (e.offsetY >= coords.Y1) && (e.offsetY < (coords.Y2 - a.Axis.LineWidth))){ - // a.drawVerticalLine(e.offsetX); - // } - // }); - a.ctx.canvas.addEventListener('mousedown', function (e) { if (!a.Enabled) { return; } - var event = a.FindEventByCoords(e.offsetX, e.offsetY); + var event = a.FindEventsByCoords(e.offsetX, e.offsetY); + if (event == null) { + return; + } - console.log(event); + if (a.Debug) console.log(event); - // console.log(e); + a.OnEventClick(event); }); } - invalidate(all) { + Invalidate(redrawAxis, redrawMarkers) { const a = this; - a.Clear(all); + if (redrawAxis) { + a.ctx.clearRect(0, 0, a.ctx.canvas.width, a.ctx.canvas.height); - if (all) { a.drawAxis(); a.drawXAxis(); a.drawXAxisLabels(); - } else { + } + + if (redrawMarkers) { + a.clearChart(); + + const visibleEvents = a.FindVisibleEvents(); const coords = a.getClientCoords(); coords.Y1 += a.Marker.Width; - for (let i=0; i 12 ? (date.getHours() - 12) : date.getHours()).toString().padStart(2, '0')); + result = result.replace("mm", date.getMinutes().toString().padStart(2, '0')); + result = result.replace("ss", date.getSeconds().toString().padStart(2, '0')); + result = result.replace("ff", date.getMilliseconds().toString().padStart(2, '0')); + result = result.replace("tt", "{5}"); + result = result.replace("zz", ""); + result = result.replace("y", date.getFullYear().toString()); + result = result.replace("M", (date.getMonth() + 1).toString()); + result = result.replace("d", date.getDate().toString()); + result = result.replace("H", date.getHours().toString()); + result = result.replace("h", (date.getHours() > 12 ? (date.getHours() - 12) : date.getHours()).toString()); + result = result.replace("m", date.getMinutes().toString()); + result = result.replace("s", date.getSeconds().toString()); + result = result.replace("z", ""); + result = result.replace("t", "{6}"); + result = result.replace("Z", ""); + + result = result.replace("{1}", date.toLocaleString('default', { month: 'long' })); + result = result.replace("{2}", date.toLocaleString('default', { weekday: 'long' })); + result = result.replace("{3}", date.toLocaleString('default', { month: 'short' })); + result = result.replace("{4}", date.toLocaleString('default', { weekday: 'short' })); + result = result.replace("{5}", (date.getHours() >= 12 ? "PM" : "AM")); + result = result.replace("{6}", (date.getHours() >= 12 ? "P" : "A")); + + return result; + } + + OnEventClick(event) { + } + + + calcGraphArea() { + const a = this; + + let result = { + X: a.Padding.Left, + Y: a.Padding.Top, + Width: (a.Size.Width - a.Padding.Right), + Height: (a.Size.Height - a.Padding.Bottom), + Margin: (a.Marker.BorderWidth * 2) + }; + + result.StepHeight = a.Marker.Width + result.Margin; + result.NoStep = Math.floor(result.Height / result.StepHeight); + + return result; + } + + calcMarkerPosition(x, y) { + const a = this; + + // Calculate Y position + let hasMoved = false; + let posY = y; + for (let i=0; i 12 ? (date.getHours() - 12) : date.getHours()).toString().padStart(2, '0')); - result = result.replace("mm", date.getMinutes().toString().padStart(2, '0')); - result = result.replace("ss", date.getSeconds().toString().padStart(2, '0')); - result = result.replace("ff", date.getMilliseconds().toString().padStart(2, '0')); - result = result.replace("tt", "{5}"); - result = result.replace("zz", ""); - result = result.replace("y", date.getFullYear().toString()); - result = result.replace("M", (date.getMonth() + 1).toString()); - result = result.replace("d", date.getDate().toString()); - result = result.replace("H", date.getHours().toString()); - result = result.replace("h", (date.getHours() > 12 ? (date.getHours() - 12) : date.getHours()).toString()); - result = result.replace("m", date.getMinutes().toString()); - result = result.replace("s", date.getSeconds().toString()); - result = result.replace("z", ""); - result = result.replace("t", "{6}"); - result = result.replace("Z", ""); - - result = result.replace("{1}", date.toLocaleString('default', { month: 'long' })); - result = result.replace("{2}", date.toLocaleString('default', { weekday: 'long' })); - result = result.replace("{3}", date.toLocaleString('default', { month: 'short' })); - result = result.replace("{4}", date.toLocaleString('default', { weekday: 'short' })); - result = result.replace("{5}", (date.getHours() >= 12 ? "PM" : "AM")); - result = result.replace("{6}", (date.getHours() >= 12 ? "P" : "A")); - - return result; - } - stringToDate(value) { return new Date(Date.parse(value)); } diff --git a/demo-test.html b/demo-test.html index e13e5c4..ac46b4c 100644 --- a/demo-test.html +++ b/demo-test.html @@ -10,9 +10,7 @@ - - @@ -23,9 +21,18 @@

- - - + + +

+

+ + + +

+

+ + +