Canvas Project
For my final canvas project, I decided to create a dolphin jumping out of the water. Bottlenose dolphins are highly intelligent and are able to adapt to their changing environment surprisingly well. As a freshman in college, I was hoping that creating this dolphin would manifest that I too adapt to my changing environment with the same grace and diligence.
This project was difficult because of the amount of bezier and quadratic curves. Luckily, patience is one of my best qualities, but I do have to admit that I cried on three separate occasions while completing my project: once while creating the bottom water splashes, and twice while adding color and attempting to give my dolphin volume.
Below I will include a picture of my final project, the reference image, and the code used to create it:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title> dolphin </title>
<!-- import external .js scripts here -->
<!-- <script type="text/javascript" src="#" ></script> -->
<!-- modify CSS properties here -->
<style type="text/css">
body,td,th {
font-family: Monaco, "Courier New", "monospace";
font-size: 14px;
color: rgba(255,255,255,1);
}
body {
background-color: rgba(0,0,0,1);
}
#container {
position: relative;
text-align: left;
width: 95%;
height: 800px;
}
#fmxCanvas {
position: relative;
background-color:rgba(255,255,255,1);
border: rgba(255,255,255,1) thin dashed;
cursor: crosshair;
display: inline-block;
}
</style>
</head>
<body>
<div id="container">
<!-- START HTML CODE HERE -->
<canvas id="fmxCanvas" width="800" height="600"></canvas>
<div id="display"></div>
<img src="dolphin.png" id="dolphin"/>
<!-- FINISH HTML CODE HERE -->
</div>
<script>
///////////////////////////////////////////////////////////////////////
// DECLARE requestAnimFrame
var rAF = window.requestAnimFrame ||
window.mozRequestAnimFrame ||
window.webkitRequestAnimFrame ||
window.msRequestAnimFrame;
var fps = 30;
window.requestAnimFrame = (
function(callback) {
return rAF ||
function(callback) {
window.setTimeout(callback, 1000 / fps);
};
})();
///////////////////////////////////////////////////////////////////////
// DEFINE GLOBAL VARIABLES HERE
var canvas;
var context;
canvas = document.getElementById("fmxCanvas");
context = canvas.getContext("2d");
var canvas1;
var context1;
canvas1 = document.createElement("canvas");
context1 = canvas1.getContext("2d");
canvas1.width = canvas.width;
canvas1.height = canvas.height;
var display;
display = document.getElementById('display');
var counter;
///////////////////////////////////////////////////////////////////////
// DEFINE YOUR GLOBAL VARIABLES HERE
var dolphin = new Image();
dolphin= document.getElementById("dolphin");
///////////////////////////////////////////////////////////////////////
// CALL THE EVENT LISTENERS
window.addEventListener("load", setup, false);
//////////////////////////////////////////////////////////////////////
// ADD EVENT LISTENERS
canvas.addEventListener("mousemove", mousePos, false);
//////////////////////////////////////////////////////////////////////
// MOUSE COORDINATES
var stage, mouseX, mouseY;
function mousePos(event) {
stage = canvas.getBoundingClientRect();
mouseX = event.clientX - stage.left;
mouseY = event.clientY - stage.top;
}
/////////////////////////////////////////////////////////////////////
// INITIALIZE THE STARTING FUNCTION
function setup() {
/////////////////////////////////////////////////////////////////////
// DECLARE STARTING VALUES OF GLOBAL VARIABLES
counter = 0;
mouseX = canvas.width/2;
mouseY = canvas.height/2;
/////////////////////////////////////////////////////////////////////
// CALL SUBSEQUENT FUNCTIONS, as many as you need
clear(); // COVER TRANSPARENT CANVAS OR CLEAR CANVAS
draw(); // THIS IS WHERE EVERYTHING HAPPENS
}
////////////////////////////////////////////////////////////////////
// CLEAR THE CANVAS FOR ANIMATION
// USE THIS AREA TO MODIFY BKGD
function clear() {
context.clearRect(0,0,canvas.width, canvas.height);
context1.clearRect(0,0,canvas.width, canvas.height);
// clear additional contexts here if you have more than canvas1
}
////////////////////////////////////////////////////////////////////
// THIS IS WHERE EVERYTHING HAPPENS
function draw() {
counter += 0.1; // EASIER FOR SINE COSINE FUNCTIONS
if (counter > Math.PI*200) { counter = 0; } // RESET COUNTER
clear(); // USE THIS TO REFRESH THE FRAME AND CLEAR CANVAS
////////////////////////////////////////////////////////////////////
// >>>START HERE>>>START HERE>>>START HERE>>>START HERE>>>START HERE
//context.drawImage(dolphin,0,0);
//context.drawImage(dolphin,0,0);
//background
var mygrad4 =
context.createRadialGradient(217,216,205,71,316,566);
context.beginPath();
mygrad4.addColorStop(0,"rgba(217,166,95,1.00)");
mygrad4.addColorStop(0.01,"rgba(170,116,50,1.00)")
mygrad4.addColorStop(0.25,"rgba(201,146,165,1.00)");
mygrad4.addColorStop(0.75,"rgba(203,110,124,1.00)");
mygrad4.addColorStop(0.75,"rgba(190,123,190,1.00)");
mygrad4.addColorStop(1,"rgba(224,191,110,1.00)");
context.beginPath();
context.rect(0,0,800,600);
context.fillStyle = mygrad4;
context.fill();
context.closePath();
// gradients
var mygrad1 =
context.createRadialGradient(428,299,205,71,316,566);
context.beginPath();
mygrad1.addColorStop(0,"rgba(36,91,118,1.00)");
mygrad1.addColorStop(0.01,"rgba(16,87,118,1.00)")
mygrad1.addColorStop(0.25,"rgba(38,96,124,1.00)");
mygrad1.addColorStop(0.75,"rgba(66,126,153,1.00)");
mygrad1.addColorStop(0.75,"rgba(23,87,112,1.00)");
mygrad1.addColorStop(1,"rgba(38,99,127,1.00)");
var mygrad2 =
context.createRadialGradient(410,320,5,365,200,200);
context.beginPath();
mygrad2.addColorStop(0.02,"rgba(213,213,209,1.00)");
mygrad2.addColorStop(0.5,"rgba(174,174,173,1.00)");
mygrad2.addColorStop(0.75,"rgba(209,213,211,1.00)");
var mygrad3 =
context.createLinearGradient(311,139,237,131);
context.beginPath();
mygrad3.addColorStop(0,"rgba(38,100,128,1.00)");
mygrad3.addColorStop(0.02,"rgba(39,97,125,1.00)");
mygrad3.addColorStop(1,"rgba(10,63,89,1.00)");
// tail
context.beginPath();
context.moveTo(235,225);
context.bezierCurveTo(196,349,217,399,284,476);
context.bezierCurveTo(270,506,280,519,294,531);
context.bezierCurveTo(290,500,296,498,300,497);
context.bezierCurveTo(309,507,332,502,345,519);
context.bezierCurveTo(330,466,325,466,300,466);
context.bezierCurveTo(252,376,271,322,294,283);
context.closePath();
context.fillStyle= mygrad1;
context.fill();
// tail shadow
context.beginPath();
context.moveTo(238,220);
context.bezierCurveTo(197,330,217,399,284,476);
context.bezierCurveTo(190,310,234,199,273,195);
//
context.closePath();
context.fillStyle= "rgba(14,72,95,1.00)";
context.fill();
// shadow two
context.beginPath();
context.moveTo(294,523);
context.lineTo(283,476);
context.lineTo(300,498);
context.quadraticCurveTo(291,496,294,523);
context.fillStyle= "rgba(13,76,103,1.00)";
context.fill();
//belly
context.beginPath();
context.moveTo(590,204);
context.bezierCurveTo(495,96,359,199,344,214);
context.bezierCurveTo(179,372,308,449,297,466);
context.lineTo(307,466);
context.bezierCurveTo(250,308,336,242,425,213);
context.bezierCurveTo(530,187,482,195,590,204);
context.fillStyle = mygrad2;
context.fill();
// top fin
context.beginPath();
context.moveTo(349,107);
context.quadraticCurveTo(274,140,241,232);
context.quadraticCurveTo(235,236,234,227);
context.quadraticCurveTo(244,198,255,187);
context.bezierCurveTo(257,122,255,155,219,120);
context.bezierCurveTo(208,100,288,108,349,107);
context.closePath();
context.fillStyle = "rgba(36,92,119,1.00)";
context.fill();
context.lineWidth= 1;
// details/ shadows
// top fin
context.beginPath();
context.moveTo(227,112);
context.quadraticCurveTo(228,123,253,127);
context.quadraticCurveTo(256,129,279,149);
context.quadraticCurveTo(295,129,313,129);
context.quadraticCurveTo(260,183,238,233);
context.quadraticCurveTo(231,246,233,232);
context.quadraticCurveTo(240,201,255,187);
context.bezierCurveTo(257,122,255,155,219,120);
context.quadraticCurveTo(218,108,227,112);
context.closePath();
context.fillStyle= "rgba(14,72,95,1.00)";
context.fill();
// bottom fin 2
context.beginPath();
context.moveTo(441,256);
context.quadraticCurveTo(494,238,488,192);
context.quadraticCurveTo(450,189,441,256);
context.closePath();
context.fillStyle = "rgba(14,72,95,1.00)";
context.fill();
context.lineWidth= 3;
// bottom fin 1
context.beginPath();
context.moveTo(392,256);
context.bezierCurveTo(381,246,408,241,445,191);
context.quadraticCurveTo(477,180,478,198);
context.quadraticCurveTo(428,254,392,256);
context.closePath();
context.fillStyle = "rgba(38,98,126,1.00)";
context.fill();
context.lineWidth= 3;
// fin 1 shadow
context.beginPath();
context.moveTo(397,243);
context.quadraticCurveTo(428,225,449,189);
context.quadraticCurveTo(420,215,397,243);
context.fillStyle= "rgba(14,72,95,1.00)";
context.fill();
//head and body
context.beginPath();
context.moveTo(614,183);
context.bezierCurveTo(608,48,416,70,347,108);
context.quadraticCurveTo(282,134,240,230);
context.quadraticCurveTo(253,261,289,279);
context.bezierCurveTo(387,157,476,140,554,175);
context.bezierCurveTo(544,131,580,154,614,183);
context.closePath();
context.fillStyle = "rgba(37,92,119,1.00)";
context.fill();
// head
context.beginPath();
context.moveTo(520,83)
context.quadraticCurveTo(606,100,613,174);
context.quadraticCurveTo(539,129,552,173);
context.quadraticCurveTo(345,108,520,83);
context.closePath();
context.fillStyle= "rgba(37,92,119,1.00)";
context.fill();
// head
// head highlight
context.beginPath();
context.moveTo(563,116);
context.quadraticCurveTo(552,62,367,98);
context.quadraticCurveTo(513,75,563,116);
context.closePath();
context.fillStyle= "rgba(60,114,137,1.00)";
context.fill();
//eye
context.beginPath();
context.arc(539,145,7,0*Math.PI,1*Math.PI,true);
context.arc(539,145,7,1*Math.PI,0*Math.PI,true);
context.fillStyle = "rgba(89,93,95,1.00)";
context.fill();
context.lineWidth= 1;
//bottom beak
context.beginPath();
context.moveTo(626,201);
context.quadraticCurveTo(632,215,592,205);
context.quadraticCurveTo(553,175,551,173);
context.quadraticCurveTo(548,155,555,158);
context.quadraticCurveTo(585,179,620,198);
context.closePath();
context.fillStyle = "rgba(37,92,119,1.00)";
context.fill();
// face shadow
context.beginPath();
context.moveTo(552,151);
context.lineTo(618,189);
context.quadraticCurveTo(610,150,598,131);
context.quadraticCurveTo(600,154,598,165);
context.quadraticCurveTo(572,145,550,150);
context.closePath();
context.fillStyle= "rgba(14,72,95,1.00)";
context.fill();
// top beak
context.beginPath();
context.moveTo(628,204);
context.bezierCurveTo(612,152,507,142,552,161);
context.quadraticCurveTo(591,188,628,204);
context.closePath();
context.fillStyle = "rgba(37,92,119,1.00)";
context.fill();
// line for mouth
context.beginPath();
context.moveTo(627,207);
context.quadraticCurveTo(600,193,582,179);
context.strokeStyle= "rgba(58,58,58,1.00)";
context.stroke();
// pupil
context.beginPath();
context.arc(540,145,5,0.5*Math.PI,1.75*Math.PI,false);
context.arc(540,145,5,1.75*Math.PI,0.75*Math.PI,false);
context.closePath();
context.fillStyle = "rgba(1,1,3,0.83)";
context.fill();
context.lineWidth= 1;
// water splash main
context.beginPath();
context.moveTo(362,305);
context.bezierCurveTo(312,330,341,360,344,364);
context.bezierCurveTo(361,302,431,322,459,377);
context.bezierCurveTo(460,394,446,405,441,402);
context.bezierCurveTo(455,358,387,310,358,357);
context.quadraticCurveTo(342,404,375,439);
context.quadraticCurveTo(388,402,417,411);
context.bezierCurveTo(424,423,380,424,382,443);
context.quadraticCurveTo(380,455,393,484);
context.quadraticCurveTo(413,456,429,489);
context.quadraticCurveTo(428,498,422,498);
context.quadraticCurveTo(410,468,398,498);
context.quadraticCurveTo(434,584,401,601);
context.lineTo(246,600);
context.quadraticCurveTo(224,571,197,589);
context.quadraticCurveTo(183,578,194,568);
context.quadraticCurveTo(208,546,214,562);
context.bezierCurveTo(245,524,199,442,164,503);
context.quadraticCurveTo(162,510,164,515);
context.quadraticCurveTo(168,519,177,525);
context.quadraticCurveTo(164,542,147,527);
context.bezierCurveTo(128,488,209,412,230,525);
context.quadraticCurveTo(244,526,239,500);
context.quadraticCurveTo(263,518,243,555);
context.quadraticCurveTo(256,600,293,592);
context.bezierCurveTo(261,544,329,514,328,557);
context.quadraticCurveTo(318,541,310,544);
context.bezierCurveTo(280,546,318,635,358,551);
context.bezierCurveTo(361,513,356,528,348,534);
context.bezierCurveTo(360,476,343,482,331,449);
context.lineTo(329,439);
context.quadraticCurveTo(344,459,356,465);
context.quadraticCurveTo(353,412,316,414);
context.quadraticCurveTo(305,402,321,401);
context.quadraticCurveTo(335,401,351,419);
context.bezierCurveTo(305,333,320,312,362,305);
context.closePath();
context.fillStyle= "rgba(6,141,162,1.00)";
context.fill();
// white water main
context.beginPath();
context.moveTo(348,587);
context.bezierCurveTo(392,527,350,548,361,451);
context.bezierCurveTo(366,508,393,572,348,587);
context.fillStyle= "rgba(27,166,188,1.00)";
context.fill();
context.beginPath();
context.moveTo(340,375);
context.quadraticCurveTo(344,357,330,353);
context.lineTo(340,375);
context.fillStyle= "rgba(29,166,188,1.00)";
context.fill();
context.beginPath();
context.moveTo(404,591);
context.bezierCurveTo(402,570,414,578,392,501);
context.quadraticCurveTo(424,571,404,591);
context.fillStyle = "rgba(28,165,188,1.00)";
context.fill();
context.beginPath();
context.moveTo(279,602);
context.quadraticCurveTo(246,578,239,567);
context.quadraticCurveTo(244,594,279,602);
context.fillStyle= "rgba(28,165,188,1.00)";
context.fill();
context.beginPath();
context.moveTo(204,562);
context.quadraticCurveTo(195,565,198,592);
context.quadraticCurveTo(186,565,204,562);
context.fillStyle= "rgba(27,164,187,1.00)";
context.fill();
context.beginPath();
context.moveTo(183,472);
context.quadraticCurveTo(150,496,153,516);
context.quadraticCurveTo(141,490,183,472);
context.fillStyle= "rgba(10,148,171,1.00)";
context.fill();
context.beginPath();
context.moveTo(433,344);
context.bezierCurveTo(458,386,454,389,444,402);
context.quadraticCurveTo(475,386,433,344);
context.filleStyle= "rgba(27,165,187,1.00)";
context.fill();
// small water splashes top right
context.beginPath();
context.moveTo(504,280);
context.quadraticCurveTo(549,300,558,324);
context.quadraticCurveTo(532,298,504,280);
context.closePath();
context.fillStyle= "rgba(6,141,162,1.00)";
context.fill();
context.beginPath();
context.moveTo(455,286);
context.bezierCurveTo(527,291,543,350,542,363);
context.bezierCurveTo(525,355,513,307,455,286);
context.closePath();
context.fillStyle= "rgba(6,141,162,1.00)";
context.fill();
context.beginPath();
context.moveTo(385,299);
context.bezierCurveTo(446,273,499,317,492,371);
context.quadraticCurveTo(469,289,385,299);
context.closePath();
context.fillStyle= "rgba(6,141,162,1.00)";
context.fill();
// white water top right
context.beginPath();
context.moveTo(493,367);
context.quadraticCurveTo(498,338,472,314);
context.quadraticCurveTo(489,338,493,367);
context.fillStyle= "rgba(27,166,188,1.00)";
context.fill();
context.beginPath();
context.moveTo(540,361);
context.quadraticCurveTo(540,323,497,302);
context.quadraticCurveTo(526,329,540,361);
context.fillStyle= "rgba(27,166,188,1.00)";
context.fill();
// water splashes bottom left
context.beginPath();
context.moveTo(229,456);
context.bezierCurveTo(182,410,153,411,117,464);
context.bezierCurveTo(97,406,185,383,229,456);
context.closePath();
context.fillStyle= "rgba(7,140,161,1.00)";
context.fill();
context.beginPath();
context.moveTo(231,476);
context.quadraticCurveTo(185,423,171,442);
context.bezierCurveTo(170,450,196,443,231,476);
context.closePath();
context.fillStyle= "rgba(6,141,162,1.00)";
context.fill();
context.beginPath();
context.moveTo(144,470);
context.quadraticCurveTo(108,514,136,540);
context.bezierCurveTo(99,523,114,478,144,470);
context.closePath();
context.fillStyle= "rgba(6,141,162,1.00)";
context.fill();
context.beginPath();
context.moveTo(116,549);
context.quadraticCurveTo(133,564,125,584);
context.quadraticCurveTo(98,565,116,549);
context.closePath();
context.fillStyle= "rgba(6,141,162,1.00)";
context.fill();
// white water bottom left
context.beginPath();
context.moveTo(120,446);
context.quadraticCurveTo(115,420,145,416);
context.quadraticCurveTo(141,420,120,446);
context.fillStyle= "rgba(27,166,188,1.00)";
context.fill();
// bottom right splashes
context.beginPath();
context.moveTo(435,430);
context.bezierCurveTo(536,406,546,500,520,506);
context.bezierCurveTo(471,420,450,427,435,430);
context.closePath();
context.fillStyle= "rgba(6,141,162,1.00)";
context.fill();
context.beginPath();
context.moveTo(430,469);
context.bezierCurveTo(466,452,492,502,480,510);
context.bezierCurveTo(457,501,454,480,430,469);
context.closePath();
context.fillStyle= "rgba(6,141,162,1.00)";
context.fill();
context.beginPath();
context.moveTo(364,601);
context.quadraticCurveTo(702,501,799,601);
context.closePath();
context.fillStyle= "rgba(6,141,162,1.00)";
context.fill();
// white water bottom right
context.beginPath();
context.moveTo(525,499);
context.quadraticCurveTo(530,470,505,440);
context.quadraticCurveTo(512,503,525,499);
context.fillStyle= "rgba(27,166,188,1.00)";
context.fill();
context.beginPath();
context.moveTo(477,510);
context.quadraticCurveTo(470,483,468,480);
context.quadraticCurveTo(490,491,477,510);
context.fillStyle= "rgba(27,166,188,1.00)";
context.fill();
context.beginPath();
context.moveTo(448,591);
context.bezierCurveTo(515,590,621,535,735,580);
context.bezierCurveTo(621,557,603,581,448,591);
context.fillStyle= "rgba(40,174,194,1.00)";
context.fill();
// <<<END HERE<<<END HERE<<<END HERE<<<END HERE<<<END HERE<<<END HERE
///////////////////////////////////////////////////////////////////
// CREDITS
context.save();
var credits = "Sydney Poniewaz, Dolphin, FMX 210, FA 2021";
context.font = 'bold 12px Helvetica';
context.fillStyle = "rgba(0,0,0,1)"; // change the color here
context.shadowColor = "rgba(255,255,255,1)"; // change shadow color here
context.shadowBlur = 12;
context.shadowOffsetX = 2;
context.shadowOffsetY = 2;
context.fillText(credits, 10, canvas.height - 10); // CHANGE THE LOCATION HERE
context.restore();
//////////////////////////////////////////////////////////////////
// HTML DISPLAY FIELD FOR TESTING PURPOSES
display.innerHTML = Math.round(mouseX) + " || " + Math.round(mouseY) + " || counter = " + Math.round(counter);
/////////////////////////////////////////////////////////////////
// LAST LINE CREATES THE ANIMATION
requestAnimFrame(draw); // CALLS draw() every nth of a second
}
</script>
</body>
</html>
Comments
Post a Comment