// James Brink, 6/25/2020 let colorCan, shapeCan, sketchCan, shapeListCan; let borderColor = [0, 0, 0, 255]; // initial colors for shapes let fillColor = [0, 128, 0, 255]; let useFill = true; let useBorder = false; let fillLabel = ["No fill", "Fill"]; let borderLabel = ["No border", "Border"]; let d = 12; let shapes = []; let currentShape = null; let clickCounter = 0; // for clicking some shapes let shapeListShow = false; let currentItem = 100000; // make sure it doesn't happen let resetColorCnt = 100000000; // make sure it doesn't happen let resetFillCol; const boxHeight = 400; const rectNo = 254; // shapes const ellipseNo = 253; // these colors are used to identify clicks const lineNo = 252; const triangleNo = 251; const quadNo = 250; const squareNo = 249; const circleNo = 248; const deleteNo = 150; const percent = [255, 171, 83]; // transpancy options const percentText = ["None", " 1/3", " 2/3"]; const firstX = 10; const fillCircleColor = 1; // these colors are used to identify clicks const borderCircleColor = 2; const showShapeListColor = 3; const shapeOptions = { rect: {n: "rectangle", sh: rectNo, x: 1, y: 1, w: 40, h: 20, f: "yellow", b: "black", useFill: true, useBorder: false}, ellipse: {n: "ellipse", sh: ellipseNo, x: 1, y: 1, w: 40, h: 20, f: "maroon", b: "black", useFill: true, useBorder: false}, line: {n: "line", sh: lineNo, x: 1, y: 1, w: 140, h: 120, f: "white", b: "blue", useFill: false, useBorder: true}, triangle: {n: "triangle", sh: triangleNo, x: 10, y: 1, x2: 1, y2: 19, x3: 40, y3: 15, f: "green", b: "black", useFill:true, useBorder: false}, quad:{n: "quad", sh: quadNo, x: 10, y: 1, x2: 1, y2: 19, x3: 40, y3: 15, x4: 35, y4: 5, f: "orange", b: "black", useFill: true, useBorder: false}, square: {n: "square", sh: squareNo, x: 1, y: 1, w: 30, h: 30, f: "purple", b: "black", useFill: true, useBorder: false}, circle: {n: "circle", sh: circleNo, x: 1, y: 1, w: 30, h: 30, f: "lime", b: "black", useFill: true, useBorder: false}, } const shapeListItemH = 19; function setup() { angleMode(DEGREES); setupShapeCan(); setupShapeListCan(); setupColor(); setupSketchCan(); frameRate(3); } // setup function draw() { // draw the figures drawColorCan(); drawSketchCan(); if (shapeListShow) { drawShapeList(); } } // draw function setupColor() { colorCan = createCanvasClass(220, 400); //370); colorCan.parent("p5"); colorCan.background(255, 255, 255); let xCenter = colorCan.width/2; let yCenter = 100; colorCan.ellipseMode(RADIUS); colorCan.translate(xCenter, yCenter); d = 12; let r = d/2; colorCan.fill("black"); colorCan.noStroke(); colorCan.circle(0, 0, r); for (let i = 1; i <= 7; i++) { for(let angle = 0; angle < 360; angle += 60/i) { let angleRed, angleBlue, angleGreen; if (angle < 60 || angle > 300) { angleRed = 0; } else if (angle > 120 && angle < 240) { angleRed = 360; } else if (angle <= 120) { angleRed = 6 * (angle - 60); } else if (angle >= 240) { angleRed = 6 * (300 - angle); } if (angle > 60 && angle < 180) { angleBlue = 0; } else if (angle > 240) { angleBlue = 360; } else if (angle <= 60) { angleBlue = 6 * (60 - angle); } else if (angle >= 180) { angleBlue = 6 * (angle - 180); } if (angle > 180 && angle < 300) { angleGreen = 0; } else if (angle < 120) { angleGreen = 360; } else if (angle >= 300) { angleGreen = 6 * (angle - 300); } else if (angle <= 180) { angleGreen = 6 * (180 - angle); } if (i == 7) { } let mult = 255 * (i/7); let re = mult * (1 - angleRed/360); let bl = mult * (1 - angleBlue/360); let gr = mult * (1 - angleGreen/360); colorCan.fill(re, gr, bl); colorCan.circle(i * d * cos(angle), i * d * sin(angle), r); } } colorCan.resetMatrix(); colorCan.fill("AntiqueWhite"); colorCan.rect(0, 200, 220, boxHeight - 200); colorCan.fill("black"); colorCan.text("Fill color", 10, 220); colorCan.text("Border color", 10, 240); colorCan.text("Click a color circle to change fill color.", 10, 258); colorCan.text("Press a key when clicking to change", 10, 276); colorCan.text("border and line color.", 10, 294); colorCan.mouseClicked(colorClick); // fill & border options colorCan.fill(borderCircleColor, 0, 0); //border colorCan.circle(d, 178, r); colorCan.fill(fillCircleColor, 0, 0); // fill colorCan.circle(220 - d, 178, r); colorCan.text("Transpancy", 80, boxHeight - 55); colorCan.stroke(0, 0, 255, 255); colorCan.line(5, boxHeight - 20, 215, boxHeight - 20); for (i = 0; i < percent.length; i++) { colorCan.stroke(0); colorCan.fill(255, 255, 255, percent[i]); colorCan.rect(firstX + i * 80, boxHeight - 30, 40, 20); colorCan.noStroke(); colorCan.fill(0, 0, 0, percent[i]); colorCan.text(percentText[i], firstX + 5 + i * 80, boxHeight - 38); } } // setupColorCan function drawColorCan() { // update parts of the colorCan // overwrite portions of the white part ofcolorCan that will be modified colorCan.fill("white"); colorCan.rect(0, 187, 60, 11, 0, 20, 0, 0); colorCan.rect(168, 185, 50, 14); colorCan.fill("black"); if (useFill) { // display info about color choice colorCan.text(fillLabel[0], 187, 198); } else { colorCan.text(fillLabel[1], 192, 198); } if (useBorder) { // display info about border color colorCan.text(borderLabel[0], 3, 198); } else { colorCan.text(borderLabel[1], 3, 198); } // show color choices in small circles in bottom half of canvas colorCan.fill(fillColor); colorCan.circle(100, 214, d/2); colorCan.fill(borderColor); colorCan.circle(100, 235, d/2); // overwrite a places where the text about color is displayed colorCan.fill("AntiqueWhite"); colorCan.rect(110, 200, 110, 45); colorCan.fill(0); if (useFill) { colorCan.text(fillColor, 120, 220); } else { colorCan.text("No fill", 120, 220); } if (useBorder) { colorCan.text(borderColor, 120, 240); } else { colorCan.text("No border", 120, 240); } } // drawColorCan function colorClick() { if (colorCan.mouseY < 200) { let c = colorCan.get(colorCan.mouseX, colorCan.mouseY); // was either the fill/no fill or border/no border circles clicked? if (c[0] == fillCircleColor) { useFill = !useFill; currentShape.useFill = useFill; return; } else if (c[0] == borderCircleColor) { useBorder = !useBorder; currentShape.useBorder = useBorder; return; } if (keyIsPressed) { // if key pressed, change border color borderColor = copyColor(c); currentShape.b = borderColor; } else { fillColor = copyColor(c); currentShape.f = fillColor; } } else if (colorCan.mouseY > 340) { // a transparency option was clicked let fillC; if (currentShape) { fillC = currentShape.f; } else { fillC = fillColor; } print("fillC: " + fillC); for (let i = 0; i < percent.length; i++) { if (firstX + i * 80 < colorCan.mouseX && colorCan.mouseX < firstX + i * 80 + 40) { let fCol = copyColor(fillC); fCol[3] = percent[i]; if (currentShape) { currentShape.f = fCol; } fillColor = fCol; } } } } // colorClick function copyColor(aColor) {// returns color in a new array let col = []; for (let i = 0; i < aColor.length; i++) { col[i] = aColor[i]; } return col; } // copyColor function setupShapeCan() { shapeCan = createCanvasClass(150, 400); //370); shapeCan.parent("p5"); shapeCan.background(255, 204, 153); // rect shapeCan.fill(rectNo, 254, 0); shapeCan.rect(20, 10, 40, 20); shapeCan.text("click & drag", 75, 30); // ellipse shapeCan.fill(ellipseNo, 0, 253); shapeCan.ellipseMode(CORNER); shapeCan.ellipse(20, 40, 40, 20); shapeCan.text("click & drag", 75, 60); // for line, inclose in area with red = 252 shapeCan.fill(lineNo, 204, 153); // this looks like background shapeCan.noStroke(); shapeCan.rect(18, 68, 44, 24); // colors area around line shapeCan.fill(lineNo, 100, 0); shapeCan.text("click & drag", 75, 90); shapeCan.stroke(lineNo, 100, 0); shapeCan.line(20, 90, 60, 70); shapeCan.noStroke(); // for triangle shapeCan.fill(triangleNo, 100, 100); shapeCan.triangle(32, 100, 20, 120, 60, 115); shapeCan.text("3 clicks", 75, 120); // for quad shapeCan.fill(quadNo, 100, 200); shapeCan.quad(32, 130, 20, 150, 60, 146, 53, 132); shapeCan.text("4 clicks", 75, 150); // for square shapeCan.fill(squareNo, 100, 250); shapeCan.square(25, 160, 22); // forth parameter not used shapeCan.text("click & drag", 75, 180); // for circle shapeCan.fill(circleNo, 100, 150); shapeCan.circle(25, 190, 22, 22); // forth parameter not used shapeCan.text("click & drag", 75, 210); // directions shapeCan.fill("black"); shapeCan.text("Click on desired shape. It shows in the " + "upper left corner of the drawing area. Then pick colors / click" + " / drag to modify it.", 5, 227, 144); shapeCan.fill(deleteNo, 100, 100); shapeCan.rect(5, boxHeight - 50, 35, 7); shapeCan.text("Delete last shape", 50, boxHeight - 35); shapeCan.fill(deleteNo, 255, 255); shapeCan.rect(5, boxHeight - 43, 35, 10); shapeCan.fill(showShapeListColor, 0, 255); shapeCan.circle(10, boxHeight - 20, d); shapeCan.fill("blue"); shapeCan.text("Show shape list", 30, boxHeight - 9); // clicked shapeCan.mouseClicked(shapeClick); } // setupShapeCan function shapeClick() { let c = shapeCan.get(shapeCan.mouseX, shapeCan.mouseY); if (c[0] == deleteNo) { // delete the current shape if (shapes.length > 0) { --shapes.length; if (shapes.length > 0) { currentShape = shapes[shapes.length - 1]; } else { currentShape = null; } return; } } else if (c[0] == showShapeListColor) { shapeListShow = true; shapeCan.hide(); shapeListCan.show(true); return; } if (c[0] == rectNo) { shapes[shapes.length] = useShape(shapeOptions.rect); } else if (c[0] == ellipseNo) { shapes[shapes.length] = useShape(shapeOptions.ellipse); } else if (c[0] == lineNo) { shapes[shapes.length] = useShape(shapeOptions.line); } else if (c[0] == triangleNo) { shapes[shapes.length] = useShape(shapeOptions.triangle); clickCounter = 0; } else if (c[0] == quadNo) { shapes[shapes.length] = useShape(shapeOptions.quad); clickCounter = 0; } else if (c[0] == squareNo) { shapes[shapes.length] = useShape(shapeOptions.square); } else if (c[0] == circleNo) { shapes[shapes.length] = useShape(shapeOptions.circle); } currentShape = shapes[shapes.length - 1]; currentItem = shapes.length - 1; currentCounter = 0; } // shapeClick function shapeToString(aShape) { let s = "shape: " + aShape.sh + " (" + aShape.x + "," + aShape.y + ") fill color: " + aShape.f + " border color: " + aShape.b; if (aShape.sh == triangleNo) { s += " (" + aShape.x2 + "," + aShape.y2 + ") (" + aShape.x3 + "," + aShape.y3 + ")"; } else if (aShape.sh == quadNo) { s += " (" + aShape.x2 + "," + aShape.y2 + ") (" + aShape.x3 + "," + aShape.y3 + ") (" + aShape.x4 + "," + aShape.y4 + ")"; } else { s += " " + aShape.w + "x" + aShape.h; } return s; } // shapeToString function useShape(shape) { fillCol = copyColor(fillColor); borderCol = copyColor(borderColor); let newShape = {n: shape.n, sh: shape.sh, x: shape.x, y: shape.y, w: shape.w, h: shape.h, x2: shape.x2, y2: shape.y2, x3: shape.x3, y3: shape.y3, x4: shape.x4, y4: shape.y4, f: fillCol, b: borderCol, useFill: useFill, useBorder: useBorder}; if (newShape.sh == lineNo) { newShape.useBorder = true; } return newShape; } // useShape function setupSketchCan() { let sp = createSpan("  "); sp.parent("p5"); sketchCan = createCanvasClass(490, 400); sketchCan.parent("p5"); sketchCan.ellipseMode(CORNERS); sketchCan.mousePressed(sketchPress); sketchCan.mouseMoved(sketchMove); sketchCan.mouseClicked(sketchClick); sketchCan.strokeWeight(2); sketchCan.keyDown(saveSketch); } // setupSketchCan function drawSketchCan() { sketchCan.background(220); for(let i = 0; i < shapes.length; i++) { let aShape = shapes[i]; if (i == currentItem && frameCount >= resetColorCnt) { aShape.f = fillColor; } if (aShape.useFill) { sketchCan.fill(aShape.f); } else { sketchCan.noFill(); } if (aShape.useBorder) { sketchCan.stroke(aShape.b); } else { sketchCan.noStroke(); } switch (aShape.sh) { case rectNo: sketchCan.rect(aShape.x, aShape.y, aShape.w, aShape.h); break; case ellipseNo: sketchCan.ellipse(aShape.x, aShape.y, aShape.x + aShape.w, aShape.y + aShape.h); break; case lineNo: sketchCan.line(aShape.x, aShape.y, aShape.x + aShape.w, aShape.y +aShape.h); break; case triangleNo: sketchCan.triangle(aShape.x, aShape.y, aShape.x2, aShape.y2, aShape.x3, aShape.y3); break; case quadNo: sketchCan.quad(aShape.x, aShape.y, aShape.x2, aShape.y2, aShape.x3, aShape.y3, aShape.x4, aShape.y4); break; case squareNo: sketchCan.square(aShape.x, aShape.y, aShape.w); break; case circleNo: // use ellipse because CORNERS doesn't work for circles sketchCan.ellipse(aShape.x, aShape.y, aShape.x + aShape.w, aShape.y + aShape.w); break; default: print("**** ERROR: invalid shape number. Namely sh: " + aShape.sh); } } } // drawSketchCan function saveSketch() { if (key == "s") { sketchCan.saveCanvas("myCanvas.png"); } } function sketchPress() { if (currentShape == null || currentShape.sh == triangleNo || currentShape.sh == quadNo) { return; } currentShape.x = sketchCan.mouseX; currentShape.y = sketchCan.mouseY; } // sketchPress function sketchMove() { if (!mouseIsPressed || currentShape == null || currentShape.sh == triangleNo || currentShape.sh == quadNo) { return; } let deltaX = sketchCan.mouseX - currentShape.x; let deltaY = sketchCan.mouseY - currentShape.y; if (currentShape.sh == squareNo || currentShape.sh == circleNo) { let delta = max(deltaX, deltaY); currentShape.w = delta; currentShape.h = delta; } else { currentShape.w = deltaX; currentShape.h = deltaY; } } // sketchMove function sketchClick() { if (!currentShape) {return;} if (currentShape.sh == triangleNo || currentShape.sh == quadNo) { if (clickCounter == 0) { clickCounter = 1; currentShape.x = sketchCan.mouseX; currentShape.y = sketchCan.mouseY; } else if (clickCounter == 1) { clickCounter = 2; currentShape.x2 = sketchCan.mouseX; currentShape.y2 = sketchCan.mouseY; } else if (clickCounter == 2 || currentShape.sh == triangleNo){ clickCounter = 3; currentShape.x3 = sketchCan.mouseX; currentShape.y3 = sketchCan.mouseY; } else if (currentShape.sh == quadNo && clickCounter >= 3) { currentShape.x4 = sketchCan.mouseX; currentShape.y4 = sketchCan.mouseY; } } } // sketchClick function setupShapeListCan() { shapeListCan = createCanvasClass(150, 400); //370); shapeListCan.hide(); shapeListCan.parent("p5"); shapeListCan.mouseClicked(shapeListClick); shapeListCan.keyDown(shapeListKeyDown); // no item selected } // setupShapeListCan function shapeListClick() { let c = shapeListCan.get(shapeListCan.mouseX, shapeListCan.mouseY); if (c[0] == showShapeListColor) { // clicked hide button shapeListCan.hide(); shapeCan.show(true); shapeListShow = false; } else { let item = round(shapeListCan.mouseY/shapeListItemH - 2.8);// 2.8 = 3 - .2 // void getting -0 for item if (item == 0) {item = 0;} if (item < 0 || item > shapes.length - 1) { // no shape item clicked return; } // user clicked a shape item currentShape = shapes[item]; fillColor = currentShape.f; borderColor = currentShape.b; useFill = currentShape.useFill; useBorder = currentShape.useBorder; // blink the shape currentItem = item; let theShape = shapes[item]; resetFillCol = theShape.f; let changeCol = []; for (let j = 0; j < 4; j++) { changeCol[j] = (resetFillCol[j] + 128) % 255; } resetColorCnt = frameCount + frameRate(); shapes[item].f = changeCol; clickCounter = 0; // in case the shape is triangle or quad } } // shapeListClick function drawShapeList() { shapeListCan.background("LemonChiffon"); shapeListCan.fill(showShapeListColor, 0, 255); shapeListCan.noStroke(); shapeListCan.circle(15, boxHeight - 10, d); shapeListCan.fill("blue"); shapeListCan.text("Hide shape list", 30, boxHeight - 6); shapeListCan.text("Shape list", 8, 8, boxHeight - 15); for (let i = 0; i < min(shapes.length, 19); i++) { if (shapes[i].sh == lineNo) { shapeListCan.fill(shapes[i].b); } else { shapeListCan.fill(shapes[i].f); } shapeListCan.circle(15, (i + 2) * shapeListItemH - d/2, d); if (i == currentItem) { shapeListCan.fill("Blue"); } else { shapeListCan.fill("Black"); } shapeListCan.text(shapes[i].n, 30, (i + 2) * shapeListItemH); } shapeListCan.fill("Black"); let directionsTop = (shapes.length + 1.5) * shapeListItemH; let directionsLength = boxHeight - 15 - directionsTop; if (directionsLength > 20) { shapeListCan.text("Shapes are listed in the order drawn. " + "(Top one first.) " + "To edit a shape, click on it. It will blink.\n" + 'You can use the "u" or "d" keys to move the selected (blue) item ' + "up or down in the list.", 5, directionsTop, 145, directionsLength); } } // drawShapeList function shapeListKeyDown() { if (currentItem >= 0 && currentItem < shapes.length) { let temp; let index; if (key == "u") { index = (currentItem - 1); if (index < 0) { index = shapes.length - 1; } print(index); temp = shapes[currentItem]; shapes[currentItem] = shapes[index]; shapes[index] = temp; currentItem = index; } else if (key = "d") { index = (currentItem + 1); if (index > shapes.length - 1) { index = 0; } temp = shapes[currentItem]; shapes[currentItem] = shapes[index]; shapes[index] = temp; currentItem = index; } } return false; } // shapeListKeyDown