You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
4.1 KiB

/**
* Stacked Chart
*/
class StackedChart extends BarChart {
/**
* Creates a new instance of the StackedChart class
*
* @param {HTMLCanvasElement} canvas - The canvas element to draw the chart on
* @param {Array<Object>} data - The data to visualize on the chart
* @param {Object} settings - The settings for the chart
* @param {ZoomManager} zoom - The zoom manager for the chart.
*/
constructor(canvas, data, settings, zoom) {
// Call the constructor of the parent class (Chart)
super(canvas, data, settings, zoom)
}
/**
* Draws the stacked bar chart on the canvas.
*/
draw() {
// Calculate the largest total value across all categories for normalization
let largest = 0
for (let i = 0; i < this.dataLen; i++) {
let sum = 0
this.data.forEach(categ => {
categ.values[i] = Math.abs(categ.values[i]) || 0
sum += categ.values[i]
})
largest = sum > largest ? sum : largest
}
// Clear the canvas
this.clear()
// Draw the axis without displaying axis values
this.drawAxis(false)
// Calculate the size of each bar segment based on the canvas width and number of data points
let size = this.zoomBounds.width / this.dataLen
// Calculate the actual width of each bar, making it 70% of the calculated size
let bar_width = size * 0.7
// Iterate over each data point to draw the stacked bars
for (let i = 0; i < this.dataLen; i++) {
// The top position of the last stacked bar segment
let last_top = this.zoomBounds.xAxis
this.data.forEach((categ, colId) => {
// Value of the bar segment
let value = categ.values[i] || 0
// The height of the bar segment relative to the largest total value
let bar_height = value / largest * this.zoomBounds.height
// The left position of the bar segment
let left = this.zoomBounds.left + size * (i + 0.15)
// The top position of the bar segment
let top = last_top - bar_height
// Update the last top position for the next iteration
last_top = top
// Create a new Rectangle object representing the current bar
let newObject = new Rectangle(this.ctx, value, colId, left, top, bar_width, bar_height)
// Add the new Rectangle object to the list of objects
this.objects.push(newObject)
// Check if the center of the new bar is within the bounds
if (this.isInBounds(newObject.getCenter())) {
// Set the fill color to the category color
this.ctx.fillStyle = categ.color
// Set the line width to 0 to prevent drawing the border
this.ctx.lineWidth = 0
// Draw the filled rectangle representing the current bar
newObject.draw()
}
})
}
// Draw x-axis labels if enabled
if (this.settings.displayAxisValues) {
// Restore canvas state to undo region clipping
this.ctx.restore()
// Loop through each data point to draw the labels
for (let i = 0; i < this.dataLen; i++) {
let text = (i + 1).toString()
// Begin drawing the text
this.ctx.beginPath()
this.ctx.font = "16px Arial"
this.ctx.fillStyle = "black"
this.ctx.textAlign = "center"
// Calculate the position of the label
let x = this.zoomBounds.left + this.zoomBounds.width / this.dataLen * i + size / 2
let y = this.bounds.bottom + 15
// Draw the label text
this.ctx.fillText(text, x, y)
// Stroke the text
this.ctx.stroke()
// Close the path
this.ctx.closePath()
}
}
}
}

Powered by TurnKey Linux.