This collection offers a hands-on, low-level tutorial for creating custom web-based brushes. It demonstrates how to build an interactive drawing tool where users can sample textures directly from an image to create dynamic, soft-edged round or square brushes. This is a practical guide for designers and developers looking to understand and implement custom drawing functionality in JavaScript.
SIMPLE SQUARE / ROUND BRUSH SAMPER
nice simpe easy example
// Globale Variablen let img; let brushTip; let brushTipSet = false; let brushSizeSlider; let roundBrushInput; let squareBrushInput; // PGraphics-Element für die Zeichenfläche let pg; // Lädt das Bild function preload() { img = loadImage('https://picsum.photos/1280/768'); } function setup() { const canvas = createCanvas(img.width, img.height); canvas.parent('canvas-container'); // Erstellt die PGraphics-Zeichenfläche pg = createGraphics(width, height); pg.image(img, 0, 0); // Ruft die Menü-Elemente ab brushSizeSlider = document.getElementById('brushSizeSlider'); roundBrushInput = document.getElementById('roundBrush'); squareBrushInput = document.getElementById('squareBrush'); } function draw() { // 1. Zeichnet die permanente Zeichenfläche (pg) auf den Haupt-Canvas image(pg, 0, 0); // 2. Zeichnet die temporäre Pinsel-Vorschau direkt auf den Haupt-Canvas if (mouseX >= 0 && mouseX <= width && mouseY >= 0 && mouseY <= height) { drawPreview(); } // 3. Wenn die linke Maustaste gedrückt ist, zeichnet es permanent auf das PGraphics-Element if (mouseIsPressed && mouseButton === LEFT) { let currentSize = parseFloat(brushSizeSlider.value); let isRound = roundBrushInput.checked; if (brushTipSet) { const drawSize = currentSize; const aspectRatio = brushTip.width / brushTip.height; const drawWidth = drawSize * aspectRatio; const drawHeight = drawSize; pg.image(brushTip, mouseX - drawWidth / 2, mouseY - drawHeight / 2, drawWidth, drawHeight); } else { // Fallback-Pinsel mit den gewählten Einstellungen if (isRound) { pg.noStroke(); pg.fill(150, 100); pg.ellipse(mouseX, mouseY, currentSize, currentSize); } else { pg.noStroke(); pg.fill(150, 100); pg.rect(mouseX - currentSize / 2, mouseY - currentSize / 2, currentSize, currentSize); } } } } // Zeichnet die halbtransparente Vorschau direkt auf den Haupt-Canvas function drawPreview() { push(); noStroke(); let currentSize = parseFloat(brushSizeSlider.value); let isRound = roundBrushInput.checked; if (brushTipSet) { const drawSize = currentSize; const aspectRatio = brushTip.width / brushTip.height; const drawWidth = drawSize * aspectRatio; const drawHeight = drawSize; // Zeichnet die Pinselspitze halbtransparent tint(255, 128); // 50% Transparenz image(brushTip, mouseX - drawWidth / 2, mouseY - drawHeight / 2, drawWidth, drawHeight); noTint(); } else { fill(150, 100); if (isRound) { drawSoftBrush(mouseX, mouseY, currentSize, 100); } else { drawSoftSquareBrush(mouseX, mouseY, currentSize, 100); } } pop(); } function mousePressed() { if (mouseButton === RIGHT) { let currentSize = parseFloat(brushSizeSlider.value); let isRound = roundBrushInput.checked; let x = mouseX - currentSize / 2; let y = mouseY - currentSize / 2; let w = currentSize; let h = currentSize; x = constrain(x, 0, width - w); y = constrain(y, 0, height - h); // 1. Holt das Bildsegment vom PGraphics-Element let tempBrush = pg.get(x, y, w, h); // 2. Erstellt die Maske und wendet sie an tempBrush.mask(createBrushMask(w, h, isRound)); brushTip = tempBrush; brushTipSet = true; console.log("Pinselspitze ausgewählt bei:", x, y, "Größe:", w, "Form: " + (isRound ? "Rund" : "Quadratisch")); return false; } } // Erstellt die Maske (Kreis oder Quadrat) auf einem PGraphics-Element function createBrushMask(w, h, isRound) { let maskPG = createGraphics(w, h); maskPG.background(0); // Schwarzer Hintergrund = vollständig transparent maskPG.noStroke(); maskPG.fill(255); // Weiße Form = vollständig sichtbar // Weiche Kante let edgeSize = 3; for (let i = 0; i < edgeSize; i++) { let currentAlpha = map(i, 0, edgeSize - 1, 0, 255); maskPG.fill(255, currentAlpha); if (isRound) { maskPG.ellipse(w / 2, h / 2, w - i, h - i); } else { maskPG.rect(i, i, w - i * 2, h - i * 2); } } return maskPG; } // Hilfsfunktion zum Zeichnen eines runden Pinsels mit weicher Kante (für den Fallback) function drawSoftBrush(x, y, size, alpha) { noStroke(); for (let i = 0; i < 3; i++) { let currentAlpha = map(i, 0, 2, alpha, 0); fill(150, currentAlpha); ellipse(x, y, size - i * 2, size - i * 2); } } // Hilfsfunktion zum Zeichnen eines quadratischen Pinsels mit weicher Kante (für den Fallback) function drawSoftSquareBrush(x, y, size, alpha) { noStroke(); for (let i = 0; i < 3; i++) { let currentAlpha = map(i, 0, 2, alpha, 0); fill(150, currentAlpha); rect(x - (size - i * 2) / 2, y - (size - i * 2) / 2, size - i * 2, size - i * 2); } }
https://editor.p5js.org/brucexxxbanner/sketches/3318WXh3k