Project 03 – Dynamic Drawing

This was inspired by an app I used to use on my mom’s iPod as a kid. I’m not very good at drawing, so I figured I would give the user a chance to draw. I’ve created a program based on degrees of symmetry that lets you alter the size of the brush, number of brushes, color of the brush, color of the background, and movement of the drawn elements. You can also save your creation by pressing p.

symmedraw2

// variable definitions
var degOfSymmetry = 36;
var curAngle = 0;
var diameter = 10;
let drawnCircs = [];
var radiate = false;
var radiateVelocity = 1;
var showRef = true;
let currentColor = ["red", "green", "blue"];
let colorVals = [255, 255, 255];
let backgroundCols = [0, 0, 0];
var colorIndex = 0;
var currentSelect = "Currently selected: " + currentColor[colorIndex];
var whatKey = "";
var rainbowMode = false;
var rainbowCtr = 0;
var freq = 0.01;

function setup() {
    createCanvas(600, 600);
    background(220);
    text("p5.js vers 0.9.0 test.", 10, 15);
}

function draw() {
    // define background based on color arrays
    background(backgroundCols[0], backgroundCols[1], backgroundCols[2]);
    noStroke();

    // set circle color based on user choice
    let c = color(colorVals[0], colorVals[1], colorVals[2]);
    if (rainbowMode) {
        var rr = sin(rainbowCtr) * 127 + 128;
        var rg = sin(rainbowCtr + (2*PI/3)) * 127 + 128;
        var rb = sin(rainbowCtr + (4*PI/3)) * 127 + 128;
        c = color(rr, rg, rb);
    }
    fill(c);

    // self explanatory
    getAngle();

    // define a center, get relative mouse radius
    var centerX = width / 2;
    var centerY = height / 2;
    var radX = mouseX - centerX;
    var radY = mouseY - centerY;
    var mouseRad = sqrt(pow(radX, 2) + pow(radY, 2));
    
    // draw a circle for each degree of symmetry 
    for (i = 0; i < degOfSymmetry; i++) {
        var loopAngle = curAngle - (i * 2*PI / degOfSymmetry)
        var tX = centerX + mouseRad * cos(loopAngle);
        var tY = centerY + mouseRad * sin(loopAngle);
        circle(tX, tY, diameter);
        
        // add to circle history if clicked
        if (mouseIsPressed) {
            drawnCircs.push([tX, tY, diameter, c, loopAngle]);
        }
    }

    // draw each circle from history
    for (i = 0; i < drawnCircs.length; i++) {
        fill(drawnCircs[i][3]);
        circle(drawnCircs[i][0], drawnCircs[i][1], drawnCircs[i][2]);

        // if radiating, begin changing circle positions
        if (radiate) {
            drawnCircs[i][0] += radiateVelocity * cos(drawnCircs[i][4]);
            drawnCircs[i][1] += radiateVelocity * sin(drawnCircs[i][4]);
            if (drawnCircs[i][0] > width || drawnCircs[i][0] < 0) {
                drawnCircs.splice(i, 1); // remove circles for speed
            } else if (drawnCircs[i][1] > height || drawnCircs[i][1] < 0) {
                drawnCircs.splice(i, 1); // remove circles for speed
            }
        }
    }

    // increment counter for rainbow mode
    rainbowCtr = (rainbowCtr + freq) % (2*PI); 

    // display onscreen reference
    if (showRef) {
        fill(255);
        text("ref: c=change color, d=change degrees of symmetry " +
                "s=change circle size, b=background color \n" +
                "o=clear screen, r=radiate outwards, p=save screen as png " +
                "v=set radiate velocity\n q=rainbow color cycle, " +
                "up/down arrow=color/velocity val+-1, right/left arrow=+-10\n" +
                "i=change selected color, enter=hide ref, y=rainbow speed", 
                10, height - 50);
        text(currentSelect, 10, 15);
        text("RGB: " + (colorVals.toString(10)), 10, 30);
        text("Radiate Velocity " + radiateVelocity.toString(10), 10, 45);
        text("Background RGB: " + (backgroundCols.toString(10)), 10, 60);
        text("Circle Size: " + (diameter.toString(10)), 10, 75);
        text("Degrees of Symmetry: " + (degOfSymmetry.toString(10)), 10, 90);
        text("Rainbow Frequency: " + (freq.toString(10)), 10, 105);
    }
}

// gets angle from mouse pos
function getAngle() {
    curAngle = atan2(mouseY - height / 2, mouseX - width / 2);
    if (mouseX - width / 2 == 0) {
        if (mouseY - height / 2 > 0) {
            curAngle = HALF_PI;
        } else {
            curAngle = 3 * HALF_PI;
        }
    }
}

function keyPressed() {
    // checks what key is pressed, performs an action, or sets a flag
    if (key == "c") {
        whatKey = "c";
        currentSelect = "Currently selected: " + currentColor[colorIndex];
    }
    if (key == "o") {
        drawnCircs = [];
    }
    if (key == "s") {
        whatKey = "s";
        currentSelect = "Currently selected: circle size";
    }
    if (key == "b") {
        whatKey = "b";
        currentSelect = "Currently selected: background color";
    }
    if (key == "d") {
        whatKey = "d";
        currentSelect = "Currently selected: degrees of symmetry";
    }
    if (key == "r") {
        radiate = !radiate;
    }
    if (key == "q") {
        rainbowMode = !rainbowMode;
    }
    if (key == "v") {
        whatKey = "v";
        currentSelect = "Currently selected: velocity"
    }
    if (key == "p") {
        save("canvas_drawing.png");
    }
    if (key == "i") {
        colorIndex = (colorIndex + 1) % 3;
        currentSelect = "Currently selected: " + currentColor[colorIndex];
    }
    if (key == "Enter") {
        showRef = !showRef;
    }
    if (key == "y") {
        whatKey = "y";
        currentSelect = "Currently selected: Rainbow Cycle Speed";
    }

    // changing parameters that affect drawing and motion
    if (keyCode == UP_ARROW) {
        if (whatKey == "d") {
            degOfSymmetry += 1;
        }
        if (whatKey == "c") {
            colorVals[colorIndex] += 1;
        }
        if (whatKey == "v") {
            radiateVelocity += 1;
        }
        if (whatKey == "b") {
            backgroundCols[colorIndex] += 1;
        }
        if (whatKey == "s") {
            diameter += 1;
        }
        if (whatKey == "y") {
            freq += 0.01;
        }
    }
    if (keyCode == DOWN_ARROW) {
        if (whatKey == "d") {
            degOfSymmetry -= 1;
        }
        if (whatKey == "c") {
            colorVals[colorIndex] -= 1;
        }
        if (whatKey == "v") {
            radiateVelocity -= 1;
        }
        if (whatKey == "b") {
            backgroundCols[colorIndex] -= 1;
        }
        if (whatKey == "s") {
            diameter -= 1;
        }
        if (whatKey == "y") {
            freq -= 0.01;
        }
    }
    if (keyCode == RIGHT_ARROW) {
        if (whatKey == "d") {
            degOfSymmetry += 10;
        }
        if (whatKey == "c") {
            colorVals[colorIndex] += 10;
        }
        if (whatKey == "v") {
            radiateVelocity += 10;
        }
        if (whatKey == "b") {
            backgroundCols[colorIndex] += 10;
        }
        if (whatKey == "s") {
            diameter += 10;
        }
        if (whatKey == "y") {
            freq += 0.10;
        }
    }
    if (keyCode == LEFT_ARROW) {
        if (whatKey == "d") {
            degOfSymmetry -= 10;
        }
        if (whatKey == "c") {
            colorVals[colorIndex] -= 10;
        }
        if (whatKey == "v") {
            radiateVelocity -= 10;
        }
        if (whatKey == "b") {
            backgroundCols[colorIndex] -= 10;
        }
        if (whatKey == "s") {
            diameter -= 10;
        }
        if (whatKey == "y") {
            freq -= 0.10;
        }
    }

    return false;
}

Getting the symmetry correct was a little difficult, as well as figuring out how to deal with user input.

Leave a Reply