2023-10-18 13:44:49 +00:00
|
|
|
class BBTimelineCanvas {
|
|
|
|
constructor(parentEl, el) {
|
|
|
|
const a = this;
|
|
|
|
|
|
|
|
a.Parent = parentEl;
|
|
|
|
a.Container = el;
|
|
|
|
a.CTX = a.Container.getContext("2d");
|
|
|
|
|
|
|
|
a.initialiseComponents();
|
|
|
|
}
|
|
|
|
|
|
|
|
initialiseComponents() {
|
|
|
|
const a = this;
|
|
|
|
|
|
|
|
a.Container.style.width = a.Parent.Size.W + "px";
|
|
|
|
a.Container.style.height = a.Parent.Size.H + "px";
|
|
|
|
a.Container.style.position = 'absolute';
|
|
|
|
a.Container.style.border = 'none';
|
|
|
|
|
|
|
|
a.CTX.canvas.width = a.Parent.Size.W;
|
|
|
|
a.CTX.canvas.height = a.Parent.Size.H;
|
|
|
|
|
|
|
|
a.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-10-22 21:14:12 +00:00
|
|
|
get ClientRectangle() {
|
|
|
|
const a = this;
|
|
|
|
|
|
|
|
return {
|
|
|
|
X: a.Parent.Padding.Left,
|
|
|
|
Y: a.Parent.Padding.Top,
|
|
|
|
W: (a.Parent.Size.W - (a.Parent.Padding.Left + a.Parent.Padding.Right)),
|
|
|
|
H: (a.Parent.Size.H - (a.Parent.Padding.Top + a.Parent.Padding.Bottom))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-10-19 23:22:29 +00:00
|
|
|
Clear() {
|
|
|
|
const a = this;
|
|
|
|
|
|
|
|
a.CTX.clearRect(0, 0, a.CTX.canvas.width, a.CTX.canvas.height);
|
|
|
|
}
|
|
|
|
|
|
|
|
Invalidate() {
|
|
|
|
// placeholder
|
|
|
|
}
|
|
|
|
|
2023-10-22 21:14:12 +00:00
|
|
|
drawCircle(x, y, width, borderWidth, borderColour, backColour) {
|
|
|
|
const a = this;
|
|
|
|
const calcBorderWidth = (borderWidth * 2);
|
|
|
|
const calcWidth = width - calcBorderWidth;
|
|
|
|
const offset = a.half(width);
|
|
|
|
|
|
|
|
a.CTX.beginPath();
|
|
|
|
a.CTX.arc(x, y, calcWidth, 0, 2 * Math.PI, false);
|
|
|
|
a.CTX.fillStyle = backColour;
|
|
|
|
a.CTX.fill();
|
|
|
|
a.CTX.lineWidth = borderWidth;
|
|
|
|
a.CTX.strokeStyle = borderColour;
|
|
|
|
a.CTX.stroke();
|
|
|
|
|
|
|
|
const result = {
|
|
|
|
X: x - (offset + borderWidth),
|
|
|
|
Y: y - (offset + borderWidth),
|
|
|
|
W: (width + calcBorderWidth),
|
|
|
|
H: (width + calcBorderWidth)
|
|
|
|
};
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
drawRectangle(rectangle, colour) {
|
|
|
|
const a = this;
|
|
|
|
|
|
|
|
a.CTX.beginPath();
|
|
|
|
a.CTX.rect(rectangle.X, rectangle.Y, rectangle.W, rectangle.H);
|
|
|
|
//a.ctx.fillStyle = 'yellow';
|
|
|
|
//a.ctx.fill();
|
|
|
|
a.CTX.lineWidth = 1;
|
|
|
|
a.CTX.strokeStyle = colour;
|
|
|
|
a.CTX.stroke();
|
|
|
|
|
|
|
|
return rectangle;
|
|
|
|
}
|
2023-10-19 23:22:29 +00:00
|
|
|
|
2023-10-18 13:44:49 +00:00
|
|
|
drawText(x, y, label, font, foreColour, align) {
|
|
|
|
const a = this;
|
|
|
|
|
|
|
|
a.CTX.font = font;
|
|
|
|
a.CTX.fillStyle = foreColour;
|
|
|
|
|
2023-10-22 21:14:12 +00:00
|
|
|
let size = a.measureText(font, label);
|
|
|
|
size.Y = y;
|
2023-10-18 13:44:49 +00:00
|
|
|
|
|
|
|
switch (align) {
|
|
|
|
case "center":
|
2023-10-22 21:14:12 +00:00
|
|
|
size.X = (x - size.X);
|
2023-10-18 13:44:49 +00:00
|
|
|
break;
|
|
|
|
case "right":
|
2023-10-22 21:14:12 +00:00
|
|
|
size.X = (x - size.W);
|
2023-10-18 13:44:49 +00:00
|
|
|
break;
|
|
|
|
case "left":
|
|
|
|
default:
|
2023-10-22 21:14:12 +00:00
|
|
|
size.X = x;
|
2023-10-18 13:44:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-10-22 21:14:12 +00:00
|
|
|
a.CTX.fillText(label, size.X, (size.Y + size.H));
|
2023-10-18 13:44:49 +00:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2023-10-22 21:14:12 +00:00
|
|
|
drawVerticalLine(x, y1, y2, width, colour) {
|
2023-10-18 13:44:49 +00:00
|
|
|
const a = this;
|
|
|
|
|
|
|
|
a.CTX.beginPath();
|
2023-10-22 21:14:12 +00:00
|
|
|
a.CTX.moveTo(x, y1);
|
|
|
|
a.CTX.lineTo(x, (y2 - width));
|
|
|
|
a.CTX.lineWidth = width;
|
2023-10-18 13:44:49 +00:00
|
|
|
a.CTX.strokeStyle = colour;
|
|
|
|
a.CTX.stroke();
|
2023-10-22 21:14:12 +00:00
|
|
|
|
|
|
|
const result = {
|
|
|
|
X: x,
|
|
|
|
Y: y1,
|
|
|
|
W: width,
|
|
|
|
H: (y2 - y1)
|
|
|
|
};
|
|
|
|
|
|
|
|
return result;
|
2023-10-18 13:44:49 +00:00
|
|
|
}
|
|
|
|
|
2023-10-22 21:14:12 +00:00
|
|
|
|
2023-10-18 13:44:49 +00:00
|
|
|
half(value) {
|
|
|
|
return (value / 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
measureText(font, value) {
|
|
|
|
const a = this;
|
|
|
|
|
|
|
|
a.CTX.font = font;
|
|
|
|
const size = a.CTX.measureText(value);
|
|
|
|
|
|
|
|
return {
|
2023-10-22 21:14:12 +00:00
|
|
|
W: size.width,
|
|
|
|
H: size.fontBoundingBoxAscent,
|
|
|
|
X: a.half(size.width),
|
|
|
|
Y: a.half(size.fontBoundingBoxAscent)
|
2023-10-18 13:44:49 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-10-22 21:14:12 +00:00
|
|
|
isPointInRectangle(rect, point) {
|
|
|
|
const x2 = (rect.X + rect.W);
|
|
|
|
const y2 = (rect.Y + rect.H);
|
|
|
|
|
|
|
|
return ((point.X >= rect.X) && (point.X <= x2) && (point.Y >= rect.Y) && (point.Y <= y2));
|
|
|
|
}
|
|
|
|
|
|
|
|
combineRectangle(rect1, rect2) {
|
|
|
|
const x2 = Math.max((rect1.X + rect1.W), (rect2.X + rect2.W));
|
|
|
|
const y2 = Math.max((rect1.Y + rect1.H), (rect2.Y + rect2.H));
|
|
|
|
|
|
|
|
const rect = {
|
|
|
|
X: Math.min(rect1.X, rect2.X),
|
|
|
|
Y: Math.min(rect1.Y, rect2.Y),
|
|
|
|
W: 0,
|
|
|
|
H: 0
|
|
|
|
};
|
|
|
|
|
|
|
|
rect.W = x2 - rect.X;
|
|
|
|
rect.H = y2 - rect.Y;
|
|
|
|
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
2023-10-18 13:44:49 +00:00
|
|
|
}
|