Files
hakorune/examples/wasm/08_data_chart.hako

457 lines
14 KiB
Plaintext
Raw Normal View History

// 📈 Real-time Data Chart Demo - TimerBox + WebCanvasBox + RandomBox
// Dynamic chart visualization with multiple chart types and data streaming
print("📈 === Real-time Data Chart Demo Starting ===")
// Initialize components
local canvas, timer, random
canvas = new WebCanvasBox("demo-canvas", 800, 500)
timer = new TimerBox()
random = new RandomBox()
// Chart configuration
local chartConfig
chartConfig = {
type: "line", // line, bar, area, scatter
title: "Nyash Performance Metrics",
width: 700,
height: 350,
marginLeft: 80,
marginTop: 50,
marginRight: 50,
marginBottom: 80,
maxDataPoints: 50,
updateInterval: 100, // milliseconds
colors: ["#3498db", "#e74c3c", "#2ecc71", "#f39c12", "#9b59b6"]
}
// Data series
local dataSeries
dataSeries = [
{name: "Memory Usage", data: [], color: "#3498db", unit: "MB"},
{name: "CPU Usage", data: [], color: "#e74c3c", unit: "%"},
{name: "Network I/O", data: [], color: "#2ecc71", unit: "KB/s"},
{name: "Disk Usage", data: [], color: "#f39c12", unit: "GB"}
]
// Chart drawing functions
local drawAxes
drawAxes = function() {
local plotX, plotY, plotWidth, plotHeight
plotX = chartConfig.marginLeft
plotY = chartConfig.marginTop
plotWidth = chartConfig.width - chartConfig.marginLeft - chartConfig.marginRight
plotHeight = chartConfig.height - chartConfig.marginTop - chartConfig.marginBottom
// Draw axes
canvas.setStrokeStyle("#34495e")
canvas.setLineWidth(2)
// Y axis
canvas.drawLine(plotX, plotY, plotX, plotY + plotHeight, "#34495e", 2)
// X axis
canvas.drawLine(plotX, plotY + plotHeight, plotX + plotWidth, plotY + plotHeight, "#34495e", 2)
// Grid lines
canvas.setStrokeStyle("#ecf0f1")
canvas.setLineWidth(1)
local i, x, y
// Vertical grid lines
i = 1
loop(i < 10) {
x = plotX + (plotWidth / 10) * i
canvas.drawLine(x, plotY, x, plotY + plotHeight, "#ecf0f1", 1)
i = i + 1
}
// Horizontal grid lines
i = 1
loop(i < 8) {
y = plotY + (plotHeight / 8) * i
canvas.drawLine(plotX, y, plotX + plotWidth, y, "#ecf0f1", 1)
i = i + 1
}
}
local drawLabels
drawLabels = function() {
local plotX, plotY, plotWidth, plotHeight
plotX = chartConfig.marginLeft
plotY = chartConfig.marginTop
plotWidth = chartConfig.width - chartConfig.marginLeft - chartConfig.marginRight
plotHeight = chartConfig.height - chartConfig.marginTop - chartConfig.marginBottom
// Y axis labels
canvas.setFillStyle("#2c3e50")
local i, value, y
i = 0
loop(i <= 8) {
value = 100 - (i * 12.5) // 0-100 scale
y = plotY + (plotHeight / 8) * i
canvas.fillText(value.toString(), plotX - 30, y + 5, "12px Arial", "#2c3e50")
i = i + 1
}
// X axis labels (time)
i = 0
loop(i <= 10) {
local timeLabel, x
timeLabel = "-" + (10 - i) + "s"
x = plotX + (plotWidth / 10) * i
canvas.fillText(timeLabel, x - 10, plotY + plotHeight + 20, "12px Arial", "#2c3e50")
i = i + 1
}
// Axis titles
canvas.fillText("Time", plotX + plotWidth / 2 - 20, plotY + plotHeight + 50, "14px Arial", "#2c3e50")
// Y axis title (rotated)
canvas.fillText("Value", 20, plotY + plotHeight / 2, "14px Arial", "#2c3e50")
}
local drawLineChart
drawLineChart = function() {
local plotX, plotY, plotWidth, plotHeight
plotX = chartConfig.marginLeft
plotY = chartConfig.marginTop
plotWidth = chartConfig.width - chartConfig.marginLeft - chartConfig.marginRight
plotHeight = chartConfig.height - chartConfig.marginTop - chartConfig.marginBottom
local i, series
i = 0
loop(i < dataSeries.length()) {
series = dataSeries[i]
if (series.data.length() > 1) {
canvas.setStrokeStyle(series.color)
canvas.setLineWidth(3)
canvas.beginPath()
local j, x, y, value
j = 0
loop(j < series.data.length()) {
value = series.data[j]
x = plotX + (j / (chartConfig.maxDataPoints - 1)) * plotWidth
y = plotY + plotHeight - (value / 100) * plotHeight
if (j == 0) {
canvas.moveTo(x, y)
} else {
canvas.lineTo(x, y)
}
j = j + 1
}
canvas.stroke(series.color, 3)
// Draw data points
j = 0
loop(j < series.data.length()) {
value = series.data[j]
x = plotX + (j / (chartConfig.maxDataPoints - 1)) * plotWidth
y = plotY + plotHeight - (value / 100) * plotHeight
canvas.setFillStyle(series.color)
canvas.fillCircle(x, y, 4)
j = j + 1
}
}
i = i + 1
}
}
local drawBarChart
drawBarChart = function() {
local plotX, plotY, plotWidth, plotHeight
plotX = chartConfig.marginLeft
plotY = chartConfig.marginTop
plotWidth = chartConfig.width - chartConfig.marginLeft - chartConfig.marginRight
plotHeight = chartConfig.height - chartConfig.marginTop - chartConfig.marginBottom
if (dataSeries[0].data.length() > 0) {
local barWidth, spacing, i, series, value, x, y, height
barWidth = (plotWidth / chartConfig.maxDataPoints) * 0.8
spacing = (plotWidth / chartConfig.maxDataPoints) * 0.2
local dataIndex
dataIndex = dataSeries[0].data.length() - 1
i = 0
loop(i < dataSeries.length()) {
series = dataSeries[i]
if (dataIndex < series.data.length()) {
value = series.data[dataIndex]
x = plotX + plotWidth - barWidth * (i + 1) - spacing * i
height = (value / 100) * plotHeight
y = plotY + plotHeight - height
canvas.setFillStyle(series.color)
canvas.fillRect(x, y, barWidth * 0.8, height)
// Value label
canvas.setFillStyle("#2c3e50")
canvas.fillText(value.toString(), x + 5, y - 10, "10px Arial", "#2c3e50")
}
i = i + 1
}
}
}
local drawAreaChart
drawAreaChart = function() {
local plotX, plotY, plotWidth, plotHeight
plotX = chartConfig.marginLeft
plotY = chartConfig.marginTop
plotWidth = chartConfig.width - chartConfig.marginLeft - chartConfig.marginRight
plotHeight = chartConfig.height - chartConfig.marginTop - chartConfig.marginBottom
local i, series
i = 0
loop(i < dataSeries.length()) {
series = dataSeries[i]
if (series.data.length() > 1) {
// Create area fill
canvas.beginPath()
local j, x, y, value
j = 0
loop(j < series.data.length()) {
value = series.data[j]
x = plotX + (j / (chartConfig.maxDataPoints - 1)) * plotWidth
y = plotY + plotHeight - (value / 100) * plotHeight
if (j == 0) {
canvas.moveTo(x, plotY + plotHeight)
canvas.lineTo(x, y)
} else {
canvas.lineTo(x, y)
}
j = j + 1
}
// Close the area
canvas.lineTo(plotX + plotWidth, plotY + plotHeight)
canvas.lineTo(plotX, plotY + plotHeight)
canvas.closePath()
// Fill with semi-transparent color
local fillColor
fillColor = series.color.replace(")", ", 0.3)")
if (series.color.startsWith("#")) {
// Convert hex to rgba
fillColor = series.color + "80" // Add alpha
}
canvas.fill(fillColor)
// Draw border line
canvas.setStrokeStyle(series.color)
canvas.setLineWidth(2)
canvas.beginPath()
j = 0
loop(j < series.data.length()) {
value = series.data[j]
x = plotX + (j / (chartConfig.maxDataPoints - 1)) * plotWidth
y = plotY + plotHeight - (value / 100) * plotHeight
if (j == 0) {
canvas.moveTo(x, y)
} else {
canvas.lineTo(x, y)
}
j = j + 1
}
canvas.stroke(series.color, 2)
}
i = i + 1
}
}
// Legend drawing
local drawLegend
drawLegend = function() {
local legendX, legendY, i, series
legendX = chartConfig.width - chartConfig.marginRight - 150
legendY = chartConfig.marginTop + 20
// Legend background
canvas.setFillStyle("#f8f9fa")
canvas.fillRect(legendX - 10, legendY - 10, 160, dataSeries.length() * 25 + 20)
canvas.setStrokeStyle("#dee2e6")
canvas.strokeRect(legendX - 10, legendY - 10, 160, dataSeries.length() * 25 + 20)
canvas.setFillStyle("#2c3e50")
canvas.fillText("Legend", legendX, legendY, "14px Arial", "#2c3e50")
i = 0
loop(i < dataSeries.length()) {
series = dataSeries[i]
// Color box
canvas.setFillStyle(series.color)
canvas.fillRect(legendX, legendY + 15 + i * 25, 15, 15)
// Series name and latest value
canvas.setFillStyle("#2c3e50")
local latestValue, valueText
if (series.data.length() > 0) {
latestValue = series.data[series.data.length() - 1]
valueText = series.name + ": " + latestValue + series.unit
} else {
valueText = series.name + ": --"
}
canvas.fillText(valueText, legendX + 20, legendY + 27 + i * 25, "12px Arial", "#2c3e50")
i = i + 1
}
}
// Data generation
local generateDataPoint
generateDataPoint = function(seriesIndex) {
local baseValue, variation, value
if (seriesIndex == 0) { // Memory Usage
baseValue = 45
variation = random.randInt(-5, 15)
} else if (seriesIndex == 1) { // CPU Usage
baseValue = 35
variation = random.randInt(-10, 25)
} else if (seriesIndex == 2) { // Network I/O
baseValue = 25
variation = random.randInt(-15, 30)
} else { // Disk Usage
baseValue = 60
variation = random.randInt(-3, 8)
}
value = baseValue + variation
return Math.max(0, Math.min(100, value))
}
// Update data
local updateData
updateData = function() {
local i, series, newValue
i = 0
loop(i < dataSeries.length()) {
series = dataSeries[i]
newValue = generateDataPoint(i)
// Add new data point
series.data.push(newValue)
// Remove old data points if exceeding max
if (series.data.length() > chartConfig.maxDataPoints) {
series.data.removeFirst()
}
i = i + 1
}
}
// Main chart drawing function
local drawChart
drawChart = function() {
// Clear canvas
canvas.setFillStyle("#ffffff")
canvas.fillRect(0, 0, 800, 500)
// Title
canvas.setFillStyle("#2c3e50")
canvas.fillText(chartConfig.title, 250, 30, "20px Arial", "#2c3e50")
// Chart type indicator
canvas.fillText("Chart Type: " + chartConfig.type.toUpperCase(), 50, 30, "16px Arial", "#34495e")
// Draw chart elements
drawAxes()
drawLabels()
if (chartConfig.type == "line") {
drawLineChart()
} else if (chartConfig.type == "bar") {
drawBarChart()
} else if (chartConfig.type == "area") {
drawAreaChart()
}
drawLegend()
// Status info
canvas.setFillStyle("#6c757d")
local statusText
statusText = "Data Points: " + dataSeries[0].data.length() + "/" + chartConfig.maxDataPoints + " | Update Rate: " + chartConfig.updateInterval + "ms"
canvas.fillText(statusText, 50, 480, "12px Arial", "#6c757d")
}
// Initialize with some sample data
local i
i = 0
loop(i < 10) {
updateData()
i = i + 1
}
// Draw initial chart
drawChart()
// Simulate real-time updates
local updateCount
updateCount = 0
local simulateUpdates
simulateUpdates = function() {
local frameCount
frameCount = 0
loop(frameCount < 20) {
updateData()
drawChart()
frameCount = frameCount + 1
updateCount = updateCount + 1
}
}
simulateUpdates()
print("📈 Real-time Data Chart Demo Ready!")
print("• Chart type: " + chartConfig.type)
print("• Data series: " + dataSeries.length())
print("• Max data points: " + chartConfig.maxDataPoints)
print("• Update interval: " + chartConfig.updateInterval + "ms")
print("• Total updates: " + updateCount)
// Demo different chart types
local chartTypes
chartTypes = ["line", "bar", "area"]
i = 0
loop(i < chartTypes.length()) {
chartConfig.type = chartTypes[i]
drawChart()
print("✓ Rendered " + chartTypes[i] + " chart")
i = i + 1
}
// Set back to line chart
chartConfig.type = "line"
drawChart()
print("🌟 Advanced chart features:")
print("• Multiple visualization types (line, bar, area)")
print("• Real-time data streaming with history")
print("• Professional grid system and axes")
print("• Interactive legend with current values")
print("• Responsive layout with proper margins")
print("• Data point management with rolling buffer")
print("🌐 Everything is Box - even data visualization!")
print("✅ Real-time Data Chart Demo Complete!")