Compare commits

..

6 Commits

12 changed files with 2586 additions and 136 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/dist
/node_modules

4
bbtimeline.min.js vendored
View File

@ -1,4 +0,0 @@
/**
* BBTimeline
* @version v0.1.1.121 beta (2023/10/18 2058)
*/

View File

@ -10,11 +10,13 @@
<!-- <script src="http://cdn.hiimray.co.uk/8206c600-707c-469e-8d49-a76ae35782af/bootstrap/5.3.0/dist/js/bootstrap.bundle.min.js"></script> -->
<!-- <link href="http://cdn.hiimray.co.uk/8206c600-707c-469e-8d49-a76ae35782af/bootstrap/5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" /> -->
<script src="bbtimeline.js"></script>
<script src="bbtimeline-canvas.js"></script>
<script src="bbtimeline-background-canvas.js"></script>
<script src="bbtimeline-flourish-canvas.js"></script>
<script src="bbtimeline-foreground-canvas.js"></script>
<script src="dist//timeline.min.js"></script>
<!-- <script src="bbtimeline.js"></script> -->
<!-- <script src="bbtimeline-canvas.js"></script> -->
<!-- <script src="bbtimeline-background-canvas.js"></script> -->
<!-- <script src="bbtimeline-flourish-canvas.js"></script> -->
<!-- <script src="bbtimeline-foreground-canvas.js"></script> -->
<!-- <script src="bbtimeline.min.js"></script> -->
@ -145,7 +147,7 @@ textarea {
<script>
var timeline1 = new BBTimeline("myCanvas");
var timeline1 = new LiteRyzJS.Timeline("myCanvas");
timeline1.OnMouseDown = function(sender, e, event) {
LogInfo("");
LogInfo("OnMouseDown");
@ -197,12 +199,13 @@ function ToggleShowLabel() {
}
function ToggleXAxisPosition() {
if (timeline1.XAxis.Position == 'top') {
timeline1.XAxis.Position = 'bottom';
const xAxis = timeline1.Layer.Background.Options.XAxis;
if (xAxis.Position == 'top') {
xAxis.Position = 'bottom';
timeline1.Padding.Top = 20;
timeline1.Padding.Bottom = 0;
} else {
timeline1.XAxis.Position = 'top';
xAxis.Position = 'top';
timeline1.Padding.Top = 0;
timeline1.Padding.Bottom = 20;
}
@ -211,7 +214,8 @@ function ToggleXAxisPosition() {
}
function ToggleMarkerTail() {
timeline1.MarkerLabel.Line.Width = ((timeline1.MarkerLabel.Line.Width <= 0) ? 1 : 0);
timeline1.Layer.Markers.Options.Label.Line.Width = ((timeline1.Layer.Markers.Options.Label.Line.Width <= 0) ? 1 : 0);
timeline1.Invalidate(true, true);
}

2343
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

11
package.json Normal file
View File

@ -0,0 +1,11 @@
{
"name": "LiteRyzJS/Timeline",
"version": "0.2.0.121",
"devDependencies": {
"webpack": "^5.93.0",
"webpack-cli": "^5.1.4"
},
"scripts": {
"build": "webpack"
}
}

5
src/index.js Normal file
View File

@ -0,0 +1,5 @@
// src/index.js
import Timeline from './timeline/timeline.js';
export { Timeline };

View File

@ -1,14 +1,34 @@
class BBTimelineBackgroundCanvas extends BBTimelineCanvas {
import TimelineCanvas from './timeline-canvas.js';
class TimelineBackgroundCanvas extends TimelineCanvas {
constructor(parentEl, el) {
super(parentEl, el);
}
initialiseOptions() {
super.initialiseOptions();
const a = this;
a.Margin = 0;
a.StepHeight = 0;
a.NoStep = 0;
a.initialiseComponents();
a.Options = {
Axis: {
LineColour1: "#000000",
LineWidth: 1,
Font: "8pt Arial",
LabelColour: "#000000",
LabelSpacing: 6
},
XAxis: {
NoPartPerDay: 4,
HourLineSpace: 6,
HourLineHeight: 10,
HourLineColour: "#EAEAEA",
DayLineHeight: 20,
DayLineColour: "#9E9E9E",
Position: 'bottom'
}
};
}
initialiseComponents() {
@ -16,10 +36,6 @@ class BBTimelineBackgroundCanvas extends BBTimelineCanvas {
const a = this;
a.Margin = (a.Parent.Marker.BorderWidth * 2);
a.StepHeight = a.Parent.Marker.Width + a.Margin;
a.NoStep = Math.floor(a.GraphRectangle.H / a.StepHeight);
a.Invalidate();
}
@ -27,7 +43,7 @@ class BBTimelineBackgroundCanvas extends BBTimelineCanvas {
get GraphRectangle() {
const a = this;
if (a.Parent.XAxis.Position == 'top') {
if (a.Options.XAxis.Position == 'top') {
return {
X: a.ClientRectangle.X,
Y: (a.ClientRectangle.Y + a.XAxisHeight),
@ -46,9 +62,9 @@ class BBTimelineBackgroundCanvas extends BBTimelineCanvas {
get XAxisHeight() {
const a = this;
const labelSize = a.measureText(a.Parent.Axis.Font, "0");
const labelSize = a.measureText(a.Options.Axis.Font, "0");
return labelSize.H + a.Parent.Axis.LabelSpacing + (a.Parent.XAxis.DayLineHeight * 2);
return labelSize.H + a.Options.Axis.LabelSpacing + (a.Options.XAxis.DayLineHeight * 2);
}
get XAxisPositions() {
@ -72,7 +88,7 @@ class BBTimelineBackgroundCanvas extends BBTimelineCanvas {
X: x
});
x += (a.Parent.XAxis.HourLineSpace * a.Parent.XAxis.NoPartPerDay);
x += (a.Options.XAxis.HourLineSpace * a.Options.XAxis.NoPartPerDay);
date.setDate(date.getDate() + 1);
}
@ -99,7 +115,7 @@ class BBTimelineBackgroundCanvas extends BBTimelineCanvas {
a.CTX.beginPath();
if (a.Parent.XAxis.Position == 'top') {
if (a.Options.XAxis.Position == 'top') {
a.CTX.moveTo(a.GraphRectangle.X, (a.GraphRectangle.Y + a.GraphRectangle.H));
a.CTX.lineTo(a.GraphRectangle.X, a.GraphRectangle.Y);
a.CTX.lineTo((a.GraphRectangle.X + a.GraphRectangle.W), a.GraphRectangle.Y);
@ -109,27 +125,27 @@ class BBTimelineBackgroundCanvas extends BBTimelineCanvas {
a.CTX.lineTo((a.GraphRectangle.X + a.GraphRectangle.W), (a.GraphRectangle.Y + a.GraphRectangle.H));
}
a.CTX.lineWidth = a.Parent.Axis.LineWidth;
a.CTX.strokeStyle = a.Parent.Axis.LineColour1;
a.CTX.lineWidth = a.Options.Axis.LineWidth;
a.CTX.strokeStyle = a.Options.Axis.LineColour1;
a.CTX.stroke();
}
drawXAxisLabels() {
const a = this;
const labelSize = a.measureText(a.Parent.Axis.Font, "0");
const labelSize = a.measureText(a.Options.Axis.Font, "0");
let posY = 0;
let posDayY = 0;
let posMonthY = 0;
if (a.Parent.XAxis.Position == 'top') {
posY = (a.GraphRectangle.Y - a.Parent.Axis.LineWidth) - 2;
posDayY = (posY - (labelSize.H + a.Parent.XAxis.DayLineHeight));
posMonthY = (posDayY - (labelSize.H + a.Parent.Axis.LabelSpacing));
if (a.Options.XAxis.Position == 'top') {
posY = (a.GraphRectangle.Y - a.Options.Axis.LineWidth) - 2;
posDayY = (posY - (labelSize.H + a.Options.XAxis.DayLineHeight));
posMonthY = (posDayY - (labelSize.H + a.Options.Axis.LabelSpacing));
} else {
posY = (a.GraphRectangle.Y + a.GraphRectangle.H) + a.Parent.Axis.LineWidth;
posDayY = (posY + a.Parent.XAxis.DayLineHeight);
posMonthY = (posDayY + labelSize.H + a.Parent.Axis.LabelSpacing);
posY = (a.GraphRectangle.Y + a.GraphRectangle.H) + a.Options.Axis.LineWidth;
posDayY = (posY + a.Options.XAxis.DayLineHeight);
posMonthY = (posDayY + labelSize.H + a.Options.Axis.LabelSpacing);
}
a.XAxisPositions.forEach(function(e, i) {
@ -149,12 +165,12 @@ class BBTimelineBackgroundCanvas extends BBTimelineCanvas {
// // Don't write first date
// } else {
// Write date (dd)
a.drawText(e.X, posDayY, a.Parent.DateToString(date, "dd"), a.Parent.Axis.Font, a.Parent.Axis.LabelColour, "center");
a.drawText(e.X, posDayY, a.Parent.DateToString(date, "dd"), a.Options.Axis.Font, a.Options.Axis.LabelColour, "center");
// }
// Write month (MMMM) on first of the month
if (writeLabel) {
a.drawText(e.X, posMonthY, a.Parent.DateToString(date, "MMMM yyyy"), a.Parent.Axis.Font, a.Parent.Axis.LabelColour, "left");
a.drawText(e.X, posMonthY, a.Parent.DateToString(date, "MMMM yyyy"), a.Options.Axis.Font, a.Options.Axis.LabelColour, "left");
}
});
}
@ -168,14 +184,14 @@ class BBTimelineBackgroundCanvas extends BBTimelineCanvas {
let posDayY = 0;
let posHourY = 0;
if (a.Parent.XAxis.Position == 'top') {
posY = (a.GraphRectangle.Y - a.Parent.Axis.LineWidth);
posDayY = (posY - a.Parent.XAxis.DayLineHeight);
posHourY = (posY - a.Parent.XAxis.HourLineHeight);
if (a.Options.XAxis.Position == 'top') {
posY = (a.GraphRectangle.Y - a.Options.Axis.LineWidth);
posDayY = (posY - a.Options.XAxis.DayLineHeight);
posHourY = (posY - a.Options.XAxis.HourLineHeight);
} else {
posY = (a.GraphRectangle.Y + a.GraphRectangle.H) + a.Parent.Axis.LineWidth;
posDayY = (posY + a.Parent.XAxis.DayLineHeight);
posHourY = (posY + a.Parent.XAxis.HourLineHeight);
posY = (a.GraphRectangle.Y + a.GraphRectangle.H) + a.Options.Axis.LineWidth;
posDayY = (posY + a.Options.XAxis.DayLineHeight);
posHourY = (posY + a.Options.XAxis.HourLineHeight);
}
let i = 0;
@ -188,21 +204,24 @@ class BBTimelineBackgroundCanvas extends BBTimelineCanvas {
a.CTX.beginPath();
a.CTX.moveTo(startPosX, posY);
if ((i % a.Parent.XAxis.NoPartPerDay) == 0) {
if ((i % a.Options.XAxis.NoPartPerDay) == 0) {
a.CTX.lineTo(startPosX, posDayY);
a.CTX.strokeStyle = a.Parent.XAxis.DayLineColour;
a.CTX.strokeStyle = a.Options.XAxis.DayLineColour;
} else {
a.CTX.lineTo(startPosX, posHourY);
a.CTX.strokeStyle = a.Parent.XAxis.HourLineColour;
a.CTX.strokeStyle = a.Options.XAxis.HourLineColour;
}
a.CTX.lineWidth = a.Parent.Axis.LineWidth;
a.CTX.lineWidth = a.Options.Axis.LineWidth;
a.CTX.stroke();
startPosX += a.Parent.XAxis.HourLineSpace;
startPosX += a.Options.XAxis.HourLineSpace;
i++;
}
}
}
export default TimelineBackgroundCanvas;

View File

@ -1,4 +1,4 @@
class BBTimelineCanvas {
class TimelineCanvas {
constructor(parentEl, el) {
const a = this;
@ -6,9 +6,14 @@ class BBTimelineCanvas {
a.Container = el;
a.CTX = a.Container.getContext("2d");
a.initialiseOptions();
a.initialiseComponents();
}
initialiseOptions() {
// Inherit
}
initialiseComponents() {
const a = this;
@ -175,3 +180,6 @@ class BBTimelineCanvas {
}
}
export default TimelineCanvas;

View File

@ -1,6 +1,13 @@
class BBTimelineFlourishCanvas extends BBTimelineCanvas {
import TimelineCanvas from './timeline-canvas.js';
class TimelineFlourishCanvas extends TimelineCanvas {
constructor(parentEl, el) {
super(parentEl, el);
}
initialiseOptions() {
super.initialiseOptions();
const a = this;
@ -27,7 +34,9 @@ class BBTimelineFlourishCanvas extends BBTimelineCanvas {
a.drawCircle(a.XPos, posY, a.Parent.HotTrack.Width, 0, a.Parent.HotTrack.Colour, a.Parent.HotTrack.Colour);
}
}
}
export default TimelineFlourishCanvas;

View File

@ -1,10 +1,36 @@
class BBTimelineForegroundCanvas extends BBTimelineCanvas {
import TimelineCanvas from './timeline-canvas.js';
class TimelineForegroundCanvas extends TimelineCanvas {
constructor(parentEl, el) {
super(parentEl, el);
}
initialiseOptions() {
super.initialiseOptions();
const a = this;
// a.initialiseComponents();
a.Options = {
Marker: {
BorderColour: "#3A5D9C",
BorderWidth: 2,
BackColour: "#D4DEEF",
Width: 10
},
Label: {
Colour: "#3A5D9C",
Font: "9pt Arial",
Margin: {
X: 2,
Y: 10
},
Line: {
Colour: "#A6A6A6",
Width: 1,
}
}
};
}
initialiseComponents() {
@ -17,7 +43,7 @@ class BBTimelineForegroundCanvas extends BBTimelineCanvas {
return;
}
var event = a.Parent.FindEventsByCoords(e.offsetX, e.offsetY);
var event = a.Parent.FindEventsByCoords(e.offsetX, e.offsetY, false);
if (event == null) {
return;
}
@ -32,7 +58,7 @@ class BBTimelineForegroundCanvas extends BBTimelineCanvas {
return;
}
var event = a.Parent.FindEventsByCoords(e.offsetX, e.offsetY);
var event = a.Parent.FindEventsByCoords(e.offsetX, e.offsetY, false);
if (event == null) {
return;
}
@ -47,7 +73,7 @@ class BBTimelineForegroundCanvas extends BBTimelineCanvas {
return;
}
var event = a.Parent.FindEventsByCoords(e.offsetX, e.offsetY);
var event = a.Parent.FindEventsByCoords(e.offsetX, e.offsetY, false);
if (event == null) {
return;
}
@ -63,7 +89,7 @@ class BBTimelineForegroundCanvas extends BBTimelineCanvas {
return;
}
var event = a.Parent.FindEventsByCoords(e.offsetX, e.offsetY);
var event = a.Parent.FindEventsByCoords(e.offsetX, e.offsetY, false);
if (event != null) {
a.Container.style.cursor = 'pointer';
} else {
@ -96,7 +122,6 @@ class BBTimelineForegroundCanvas extends BBTimelineCanvas {
Invalidate() {
const a = this;
const rect = a.Parent.Layer.Background.GraphRectangle;
const margin = a.Parent.Layer.Background.Margin;
a.Clear();
@ -104,9 +129,9 @@ class BBTimelineForegroundCanvas extends BBTimelineCanvas {
const visibleEvents = a.Parent.VisibleEvents;
if (a.Parent.XAxis.Position == 'top') {
startPosY = (rect.Y + a.Parent.Marker.Width + 20);
startPosY = (rect.Y + a.Options.Marker.Width + 20);
} else {
startPosY = (rect.Y + a.Parent.Marker.Width);
startPosY = (rect.Y + a.Options.Marker.Width);
}
// Clear for collisions detection
@ -125,17 +150,16 @@ class BBTimelineForegroundCanvas extends BBTimelineCanvas {
posY2 = (a.Parent.Layer.Background.GraphRectangle.Y + a.Parent.Layer.Background.GraphRectangle.H);
}
if (a.Parent.MarkerLabel.Line.Width > 0) {
a.drawVerticalLine(e.Position.X, posY, posY2, a.Parent.MarkerLabel.Line.Width, a.Parent.MarkerLabel.Line.Colour);
if (a.Options.Label.Line.Width > 0) {
a.drawVerticalLine(e.Position.X, posY, posY2, a.Options.Label.Line.Width, a.Options.Label.Line.Colour);
}
const markerRectangle = a.drawCircle(e.Position.X, posY, a.Parent.Marker.Width, a.Parent.Marker.BorderWidth, e.BorderColour, e.BackColour);
const markerRectangle = a.drawCircle(e.Position.X, posY, a.Options.Marker.Width, a.Options.Marker.BorderWidth, e.BorderColour, e.BackColour);
e.Position = { X: e.Position.X, Y: posY };
if (a.Parent.ShowMarkerLabel) {
const labelRectangle = a.drawText((markerRectangle.X + markerRectangle.W + margin), markerRectangle.Y, e.Label, a.Parent.MarkerLabel.Font, a.Parent.MarkerLabel.Colour, "left");
labelRectangle.W += a.Parent.MarkerLabel.Margin;
const labelRectangle = a.drawText((markerRectangle.X + markerRectangle.W + a.Options.Label.Margin.X), markerRectangle.Y, e.Label, a.Options.Label.Font, a.Options.Label.Colour, "left");
e.HitBox = a.combineRectangle(markerRectangle, labelRectangle);
} else {
@ -152,14 +176,13 @@ class BBTimelineForegroundCanvas extends BBTimelineCanvas {
return;
}
var event = a.Parent.FindEventsByCoords(e.offsetX, e.offsetY);
var event = a.Parent.FindEventsByCoords(e.offsetX, e.offsetY, false);
if (event == null) {
return;
}
if (a.Parent.Debug) console.log(event);
console.log("!");
a.Parent.OnMouseDown(this, e, event);
}
@ -167,14 +190,13 @@ class BBTimelineForegroundCanvas extends BBTimelineCanvas {
const a = this;
const rect = a.Parent.Layer.Background.GraphRectangle;
// Calculate Y position
let hasMoved = false;
let posY = y;
for (let i=0; i<a.Parent.Layer.Background.NoStep; i++)
for (let i=rect.Y; i<(rect.Y + rect.H); i++)
{
posY = y + (a.Parent.Layer.Background.StepHeight * i);
posY = i;
var clippedEvent = a.Parent.FindEventsByCoords(x, posY);
var clippedEvent = a.Parent.FindEventsByCoords(x, posY, true);
if (clippedEvent == null) {
hasMoved = true;
break;
@ -189,3 +211,6 @@ class BBTimelineForegroundCanvas extends BBTimelineCanvas {
}
}
export default TimelineForegroundCanvas;

View File

@ -1,8 +1,9 @@
/**
* BBTimeline
* @version v0.1.1.121 beta (2023/10/18 2058)
*/
class BBTimeline {
import TimelineBackgroundCanvas from './timeline-background-canvas.js';
import TimelineFlourishCanvas from './timeline-flourish-canvas.js';
import TimelineForegroundCanvas from './timeline-foreground-canvas.js';
class Timeline {
constructor(el) {
const a = this;
@ -25,39 +26,6 @@ class BBTimeline {
a.DateParsePattern = "yyyy-MM-dd";
a.Axis = {
LineColour1: "#000000",
LineWidth: 1,
Font: "8pt Arial",
LabelColour: "#000000",
LabelSpacing: 6
};
a.XAxis = {
NoPartPerDay: 4,
HourLineSpace: 6,
HourLineHeight: 10,
HourLineColour: "#EAEAEA",
DayLineHeight: 20,
DayLineColour: "#9E9E9E",
Position: 'bottom'
};
a.Marker = {
BorderColour: "#3A5D9C",
BorderWidth: 2,
BackColour: "#D4DEEF",
Width: 10
};
a.MarkerLabel = {
Colour: "#3A5D9C",
Font: "9pt Arial",
Margin: 8,
Line: {
Colour: "#A6A6A6",
Width: 1,
}
};
a.HotTrack = {
Colour: "#F57C00",
Width: 3
@ -75,6 +43,19 @@ class BBTimeline {
a.initialiseComponents();
}
initialiseComponents() {
const a = this;
a.Container.innerHTML = "<canvas></canvas><canvas></canvas><canvas></canvas>";
const canvasList = a.Container.getElementsByTagName("canvas");
a.Layer.Background = new TimelineBackgroundCanvas(a, canvasList[0]);
a.Layer.Flourish = new TimelineFlourishCanvas(a, canvasList[1]);
a.Layer.Markers = new TimelineForegroundCanvas(a, canvasList[2]);
}
get CTX() {
return a.Layer.Markers.CTX;
@ -89,8 +70,8 @@ class BBTimeline {
Position: { X: 0, Y: 0 },
Events: [],
HitBox: null,
BorderColour: a.Marker.BorderColour,
BackColour: a.Marker.BackColour
BorderColour: a.Layer.Markers.Options.Marker.BorderColour,
BackColour: a.Layer.Markers.Options.Marker.BackColour
};
}
@ -147,6 +128,12 @@ class BBTimeline {
return result;
}
get XAxis() {
const a = this;
return a.Layer.Background.Options.XAxis;
}
AddEvent(date, label, options) {
const a = this;
@ -221,7 +208,7 @@ class BBTimeline {
return null;
}
FindEventsByCoords(x, y) {
FindEventsByCoords(x, y, addmargin) {
const a = this;
for (let i=0; i<a.Events.length; i++) {
@ -230,8 +217,12 @@ class BBTimeline {
continue;
}
const x2 = (e.X + e.W);
const y2 = (e.Y + e.H);
let x2 = (e.X + e.W);
let y2 = (e.Y + e.H);
if (addmargin) {
y2 += a.Layer.Markers.Options.Label.Margin.Y;
}
if ((x >= e.X) && (x <= x2) && (y >= e.Y) && (y <= y2)){
return a.Events[i];
@ -383,18 +374,7 @@ class BBTimeline {
OnDblClick(sender, e, event) { /* delegate */ }
initialiseComponents() {
const a = this;
a.Container.innerHTML = "<canvas></canvas><canvas></canvas><canvas></canvas>";
const canvasList = a.Container.getElementsByTagName("canvas");
a.Layer.Background = new BBTimelineBackgroundCanvas(a, canvasList[0]);
a.Layer.Flourish = new BBTimelineFlourishCanvas(a, canvasList[1]);
a.Layer.Markers = new BBTimelineForegroundCanvas(a, canvasList[2]);
}
}
export default Timeline;

48
webpack.config.js Normal file
View File

@ -0,0 +1,48 @@
const path = require('path');
const { version } = require('./package.json');
const webpack = require('webpack');
class PrependVersionPlugin {
apply(compiler) {
compiler.hooks.emit.tapAsync('PrependVersionPlugin', (compilation, callback) => {
Object.keys(compilation.assets).forEach((filename) => {
if (filename.endsWith('.js')) {
const asset = compilation.assets[filename];
const headerText = `/*!\n * LiteRyzJS/Timeline v${version}\n * Copyright 2023-2024 Ray Lam (https://www.hiimray.co.uk)\n *\n */\n`;
const newContent = headerText + asset.source();
compilation.assets[filename] = {
source: () => newContent,
size: () => newContent.length,
};
}
});
callback();
});
}
}
module.exports = {
entry: {
timeline: './src/index.js'
},
output: {
filename: `[name].dist.js`,
path: path.resolve(__dirname, 'dist'),
library: 'LiteRyzJS',
libraryTarget: 'umd',
globalObject: 'this'
},
mode: 'production', // development|production
plugins: [
new webpack.DefinePlugin({
'process.env.VERSION': JSON.stringify(version)
}),
new PrependVersionPlugin()
]
};