Leaf Shadows

In this example below you will see how to do a Leaf Shadows with some HTML / CSS and Javascript

Thumbnail
This awesome code was written by patlillis, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright patlillis ©

Technologies

  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Leaf Shadows</title>
  
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">

  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <canvas id="canvas"></canvas>

<div id="buttons">
	<button id="init">Init</button>
	<button id="redraw">Redraw</button>
</div>
  <script src='https://code.jquery.com/jquery-2.2.4.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5.1/dat.gui.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.12.0/lodash.min.js'></script>

  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/patlillis/leaf-shadows-OXyErL */
html {
  height: 100%;
}

body {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-font-smoothing: antialiased;
  -o-font-smoothing: antialiased;
  color: #fff;
  overflow: hidden;
}

#canvas {
  display: block;
  background: lightblue;
}

#buttons {
  position: absolute;
  top: 15px;
  left: 15px;
}

#buttons button {
  background: white;
  border: 1px solid blue;
}


/*Downloaded from https://www.codeseek.co/patlillis/leaf-shadows-OXyErL */
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var canvas = void 0,
    ctx = void 0,
    branches = void 0;

var options = {
	minChildLength: 0.4,
	maxChildLength: 0.7
};

$(function () {
	var $canvas = $("#canvas");
	canvas = $canvas.get(0);
	ctx = canvas.getContext("2d");

	branches = [];

	$(window).on('resize', resize);
	resize();

	$('#init').on('click', initBranches);
	$('#redraw').on('click', redraw);

	//Init gui
	var gui = new dat.GUI();
	gui.add(options, 'minChildLength', 0, 1).onChange(initBranches);
	gui.add(options, 'maxChildLength', 0, 1).onChange(initBranches);

	initBranches();
	redraw();
});

function resize() {
	var width = window.innerWidth;
	var height = window.innerHeight;

	canvas.width = width;
	canvas.height = height;
	$(canvas).css({
		width: width + 'px',
		height: height + 'px'
	});

	redraw();
}

function redraw() {
	ctx.clearRect(0, 0, canvas.width, canvas.height);
	branches.forEach(function (b) {
		return b.drawBranch();
	});
	branches.forEach(function (b) {
		return b.drawLeaves();
	});
}

function initBranches() {
	branches = [];

	var start = new Point({
		x: _.random(0.05, 0.25) * canvas.width,
		y: _.random(0.05, 0.25) * canvas.height
	});
	var length = _.random(0.5, 0.9) * Math.min(canvas.width, canvas.height);
	var angle = _.random(Math.PI / 8, 3 * (Math.PI / 8));
	var b = new Branch(start, length, angle, 1);
	branches.push(b);
	initChildBranches(b, 1.0);
	initChildBranches(b, -1.0);
	redraw();
}

function initChildBranches(parent, side) {
	//Init right side
	var distAlongParent = 0;

	while ((distAlongParent += _.random(0.2, 0.4)) < 1.0) {
		var childStart = lerp(parent.start, parent.end, distAlongParent);
		var childLength = _.random(options.minChildLength, options.maxChildLength) * parent.length;
		var childAngle = side * _.random(Math.PI / 8, 3 * (Math.PI / 8)) + parent.angle;

		if (childLength > 100) {
			var child = new Branch(childStart, childLength, childAngle, parent.depth + 1);
			branches.push(child);
			initChildBranches(child, 1.0);
			initChildBranches(child, -1.0);
		}
	}
}

var Point = function Point(x, y) {
	_classCallCheck(this, Point);

	if ($.isNumeric(x)) {
		this.x = x;
		this.y = y;
	} else {
		this.x = x.x;
		this.y = x.y;
	}
};

var Branch = function () {
	function Branch(start, length, angle, depth) {
		_classCallCheck(this, Branch);

		this.start = start;
		this.length = length;
		this.angle = angle;
		this.depth = depth;

		//Figure out end point
		this.end = new Point({
			x: start.x + Math.cos(angle) * length,
			y: start.y + Math.sin(angle) * length
		});

		//Figure out leaf points
		this.leaves = [];
		var dist = 0.0;
		while ((dist += _.random(0.1, 0.4)) < 1.0) {
			var leaf = lerp(this.start, this.end, dist);
			this.leaves.push(leaf);
		}
	}

	_createClass(Branch, [{
		key: "draw",
		value: function draw() {
			this.drawBranch();
			this.drawLeaves();
		}
	}, {
		key: "drawBranch",
		value: function drawBranch() {
			//Draw branch
			ctx.beginPath();
			ctx.lineWidth = 30 * Math.exp(-0.9 * this.depth);
			ctx.moveTo(this.start.x, this.start.y);
			ctx.lineTo(this.end.x, this.end.y);
			ctx.stroke();
		}
	}, {
		key: "drawLeaves",
		value: function drawLeaves() {
			var _this = this;

			//Draw leaves
			this.leaves.forEach(function (l) {

				var gradient = ctx.createRadialGradient(l.x, l.y, _this.leafRadius, l.x, l.y, 0);
				gradient.addColorStop(0, "rgba(255,0,0,0)");
				gradient.addColorStop(1 - _this.opacity, "rgba(255,0,0,1)");
				ctx.fillStyle = gradient;
				ctx.fillRect(l.x - _this.leafRadius, l.y - _this.leafRadius, _this.leafRadius * 2, _this.leafRadius * 2);

				// 						let fillStyle = "rgba(255, 0, 0, " + this.opacity + ")";

				// 						ctx.beginPath();
				// 						ctx.arc(l.x, l.y, this.leafRadius, 0, 2 * Math.PI);
				// 						ctx.fillStyle = fillStyle;
				// 						ctx.fill();
			});
		}
	}, {
		key: "opacity",
		get: function get() {
			return 2 * Math.exp(-0.95 * this.depth);
		}
	}, {
		key: "leafRadius",
		get: function get() {
			return 125 * Math.exp(-0.5 * this.depth) + 25;
		}
	}]);

	return Branch;
}();

function lerp(start, end, amt) {
	if (start instanceof Point) {
		return new Point({
			x: lerp(start.x, end.x, amt),
			y: lerp(start.y, end.y, amt)
		});
	} else {
		return (1 - amt) * start + amt * end;
	}
}

Comments