html,body{margin: 0;padding: 0;}
body{margin:0px; padding:0px;overflow:hidden;}
let n = 7;
let scale = 200;
let control1, control2;
let slider, methodRadio;
let aLabel, bLabel;
let isDraggingControl1 = false;
let isDraggingControl2 = false;
const colors = {
bg: '#282a36',
plot: '#F8F8F2',
controlDefault: '#4589ff',
controlDragging: '#FF79C6',
sumFill: '#44475A7A',
stroke: '#6272A4',
uiBg: '#8BE9FD',
uiText: '#F8F8F2',
uiHighlight: '#0062ff',
};
let func = (x) => Math.cos(x) + x / 3 + 0.5;
function setup() {
createCanvas(windowWidth, windowHeight);
background(colors.bg);
// Responsivo: Slider de divisão
slider = createSlider(1, 100, n);
slider.position(24, windowHeight - 50);
slider.style('width', (windowWidth - 48) + 'px');
slider.style('background-color', colors.uiBg);
slider.style('color', colors.uiText);
control1 = createVector(100, 0);
control2 = createVector(500, 0);
aLabel = createDiv("A");
bLabel = createDiv("B");
styleLabel(aLabel, control1);
styleLabel(bLabel, control2);
// Radio button de métodos de soma de Riemann
methodRadio = createRadio();
methodRadio.option('Esquerda');
methodRadio.option('Centro');
methodRadio.option('Direita');
methodRadio.option('Trapezoidal');
methodRadio.selected('Centro');
methodRadio.position(24, windowHeight * 0.05);
methodRadio.style('color', colors.uiText);
//methodRadio.style('background-color', colors.uiBg);
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
slider.style('width', (windowWidth - 48) + 'px');
//methodRadio.position(24, windowHeight * 0.05);
}
function draw() {
background(colors.bg);
stroke(colors.plot);
plotFunction();
drawRiemannSums();
updateControlPosition(control1, aLabel);
updateControlPosition(control2, bLabel);
drawControlPoint(control1, isDraggingControl1);
drawControlPoint(control2, isDraggingControl2);
handleCursor();
}
function plotFunction() {
noFill();
beginShape();
const height = windowHeight * 0.8;
const width = windowWidth - 32;
for (let x = 0; x <= width; ++x) {
vertex(x + 16, -func(x / scale) * scale + height);
}
endShape();
rect(16, 0, windowWidth - 32, windowHeight * 0.8);
}
function drawRiemannSums() {
let start = min(control1.x, control2.x);
let end = max(control1.x, control2.x);
let delta = (end - start) / slider.value();
fill(colors.sumFill);
stroke(colors.stroke);
const method = methodRadio.value(); // Método selecionado
for (let x = start; x < end - 0.0001; x += delta) {
if (method === 'Trapezoidal') {
drawTrapezoidalSum(x, delta);
} else {
drawRectangularSum(x, delta, method);
}
}
}
// Aproximação Trapezoidal Correta
function drawTrapezoidalSum(x, delta) {
let yLeft = -func(x / scale) * scale + windowHeight * 0.8;
let yRight = -func((x + delta) / scale) * scale + windowHeight * 0.8;
beginShape();
vertex(x + 16, windowHeight * 0.8);
vertex(x + 16, yLeft);
vertex(x + delta + 16, yRight);
vertex(x + delta + 16, windowHeight * 0.8);
endShape(CLOSE);
}
// Aproximação para Esquerda, Centro e Direita
function drawRectangularSum(x, delta, method) {
const baseY = windowHeight * 0.8;
let y = 0;
switch (method) {
case 'Esquerda':
y = -func(x / scale) * scale + baseY;
break;
case 'Centro':
const midX = (x + x + delta) / 2;
y = -func(midX / scale) * scale + baseY;
break;
case 'Direita':
y = -func((x + delta) / scale) * scale + baseY;
break;
default:
console.warn('Unknown method:', method);
return;
}
const height = baseY - y;
rect(x + 16, y, delta, height);
}
function updateControlPosition(control, label) {
control.y = -func(control.x / scale) * scale;
styleLabel(label, control);
}
function drawControlPoint(control, isDragging) {
fill(isDragging ? colors.controlDragging : colors.controlDefault);
noStroke();
ellipse(control.x + 16, control.y + windowHeight * 0.8, 12, 12);
}
function handleCursor() {
if (isMouseOverControl(control1) || isMouseOverControl(control2)) {
cursor(isDraggingControl1 || isDraggingControl2 ? 'grabbing' : 'grab');
} else if (!isDraggingControl1 && !isDraggingControl2) {
cursor('default');
}
}
function isMouseOverControl(control) {
return dist(mouseX, mouseY, control.x + 16, control.y + windowHeight * 0.8) < 10;
}
function mousePressed() {
if (isMouseOverControl(control1)) isDraggingControl1 = true;
else if (isMouseOverControl(control2)) isDraggingControl2 = true;
}
function mouseReleased() {
isDraggingControl1 = false;
isDraggingControl2 = false;
}
function mouseDragged() {
if (isDraggingControl1) control1.x = constrain(mouseX - 16, 0, windowWidth - 32);
else if (isDraggingControl2) control2.x = constrain(mouseX - 16, 0, windowWidth - 32);
}
function styleLabel(label, control) {
label.position(control.x + 16, windowHeight - 100);
label.style('color', colors.plot);
label.style('font-family', 'KaTeX_Math');
label.style('font-size', '22px');
label.style('text-align', 'center');
}
This Pen doesn't use any external CSS resources.