class BBTimelineCanvas { constructor(parentEl, el) { const a = this; a.Parent = parentEl; a.Container = el; a.CTX = a.Container.getContext("2d"); a.initialiseOptions(); a.initialiseComponents(); } initialiseOptions() { // Inherit } 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(); } 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)) }; } Clear() { const a = this; a.CTX.clearRect(0, 0, a.CTX.canvas.width, a.CTX.canvas.height); } Invalidate() { // placeholder } 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; } drawText(x, y, label, font, foreColour, align) { const a = this; a.CTX.font = font; a.CTX.fillStyle = foreColour; let size = a.measureText(font, label); size.Y = y; switch (align) { case "center": size.X = (x - size.X); break; case "right": size.X = (x - size.W); break; case "left": default: size.X = x; break; } a.CTX.fillText(label, size.X, (size.Y + size.H)); return size; } drawVerticalLine(x, y1, y2, width, colour) { const a = this; a.CTX.beginPath(); a.CTX.moveTo(x, y1); a.CTX.lineTo(x, (y2 - width)); a.CTX.lineWidth = width; a.CTX.strokeStyle = colour; a.CTX.stroke(); const result = { X: x, Y: y1, W: width, H: (y2 - y1) }; return result; } half(value) { return (value / 2); } measureText(font, value) { const a = this; a.CTX.font = font; const size = a.CTX.measureText(value); return { W: size.width, H: size.fontBoundingBoxAscent, X: a.half(size.width), Y: a.half(size.fontBoundingBoxAscent) }; } 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; } }