block by nbremer cbf61944aeb3204d3e4986ea645afc2b

Color blending - Infinity showcase

Full Screen

This is one of the color blending examples of my blog on Beautiful color blending effects with SVGs & D3

In this small showcase you can see the effect of using a mix-blend-mode on your SVG elements. Every 3 seconds it switches to a different set of colors or switches from “screen” to “multiply” mode and there are 7 different sets before it begins anew. In one ofthe 7 sets, it sets no blend mode and you can see with your own eyes that that version definitely has less magic :)

This example is heavily based on the wonderful particle demo of Sketch.js. I fell in love with it when I first saw it and really wanted to use it in my OpenVis presentation. Because I already thought it was perfect I only made the changes to make it run in an infinity symbol (for infinity) instead of attaching it to a mouse and to loop through several sets of colors and both the screen and multiply blend modes. Also, since I was giving a talk of using SVGs in non-standard ways in D3 I had to adjust the code and make it work with D3 alone. Performance wise, not the better option I know.

Another color blending example can be found here

Built with blockbuilder.org

index.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		
		<!-- D3.js -->
		<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>

		<link href='https://fonts.googleapis.com/css?family=Open+Sans:300' rel='stylesheet' type='text/css'>

		<style>
			html { font-size: 62.5%; } 

			.colorStatus {
				font-family: 'Open Sans';
			    font-size: 2rem;
			    fill: #989898;
			    font-weight: 300;
			  }
		</style>
	</head>	
	<body>

		<div id="infinityChart" style="text-align: center;"></div>

		<script language="javascript" type="text/javascript">

			///////////////////////////////////////////////////////////////////////////
			//////////////////// Set up and initiate svg containers ///////////////////
			///////////////////////////////////////////////////////////////////////////	

			var margin = {
				top: 0,
				right: 0,
				bottom: 0,
				left: 0
			};
			var width = window.innerWidth - margin.left - margin.right - 10,
				height = window.innerHeight - margin.top - margin.bottom - 20;
						
			//SVG container
			var svg = d3.select('#infinityChart')
				.append("svg")
				.attr("width", width + margin.left + margin.right)
				.attr("height", height + margin.top + margin.bottom)
				.append("g")
				.attr("transform", "translate(" + (margin.left + width/2) + "," + (margin.top + height/2) + ")");

			//Grey background color
			d3.select("body").style("background", "#262626");

			//Reset the overall font size
			var newFontSize = width * 62.5 / 2000;
			d3.select("html").style("font-size", newFontSize + "%");

			//Circle ranges
			var circeRanges = [8 * width/2000, 30 * width/2000];
			var forceRanges = [6 * width/2000, 10 * width/2000];

			//Blend mode info
			svg.append("text")
		    	.attr("class", "colorStatus")
		        .attr("x", 0)
		        .attr("y", height/2-10)
		        .style("text-anchor", "middle")
		        .text("mix-blend-mode: screen");

			///////////////////////////////////////////////////////////////////////////
			//////////////////////////// Set up infinity path /////////////////////////
			///////////////////////////////////////////////////////////////////////////	

			//But adjusted for D3 and made to move along a path
			var ID = 0,	//makes all particles unique
				counter = 0, //counter for the infinity path
				colors = [ '#69D2E7', '#A7DBD8', '#E0E4CC', '#F38630', '#FA6900', '#FF4E50', '#F9D423' ], //first colors
				colorMode = "screen", //first blend mode
				particles = [];

			//Create the infinity path
			//Formula from //gamedev.stackexchange.com/questions/43691/how-can-i-move-an-object-in-an-infinity-or-figure-8-trajectory
			var infScale = width/2*0.7;
			var x, y, scale;
			var infinityPath = [];
			for (var i = 0; i < 209; i++) {
				t = i*0.03;
				scale = 2 / (3 - Math.cos(2*t));
				x = scale * Math.cos(t);
				y = scale * Math.sin(2*t) / 2;
				//console.log("i: " + i + " x:" + x + " y:" + y);
				infinityPath.push({x: x*infScale, y: y*infScale});
			}//for i

			///////////////////////////////////////////////////////////////////////////
			//////////////////// Make the circles move in a pattern ///////////////////
			///////////////////////////////////////////////////////////////////////////	

			//Wrapper for the circles
			var circleWrapper = svg.append("g")
					.attr("class", "circleWrapper")
					.style("isolation", "isolate");

			function runInfinity() {

				//Create new particles
				for (var j = 0; j < Math.round(Math.random()*16); j++) spawn(infinityPath[counter].x, infinityPath[counter].y);

				//Remove non-alive particles
				particles = particles.filter(function(d) { return d.alive; });

			  	//DATA JOIN
				//Join new data with old elements, if any
				var circleGroup = circleWrapper.selectAll(".particle")
					.data(particles, function(d) { return d.id; });
			  
				//UPDATE
				circleGroup
					.style("mix-blend-mode", colorMode)
					.each(move)
					.transition("move").duration(50).ease("linear")
					.attr("cx", function(d) { return d.x; })
					.attr("cy", function(d) { return d.y; })
					.attr("r", function(d) { return d.radius; });	
			
				//ENTER 
				circleGroup
					.enter().append("circle")
					.attr("class", "particle")
					.attr("cx", function(d) { return d.x; })
					.attr("cy", function(d) { return d.y; })
					.style("fill", function(d) { return d.color; })
					.style("mix-blend-mode", colorMode)
					.attr("r", function(d) { return d.radius; });
						
				//EXIT
				circleGroup.exit().remove();	

				counter = (counter + 1)%infinityPath.length;

			}//runInfinity

			//Create an interval that runs along the infinity path
			var loopInfinity = setInterval(runInfinity , 50);

			///////////////////////////////////////////////////////////////////////////
			/////////////// Functions to create and move the particles ////////////////
			///////////////////////////////////////////////////////////////////////////	

			//Code heavily based on //codepen.io/soulwire/pen/foktm
			//Calculates new position
			function move(d) {

				d.x += d.vx;
				d.y += d.vy;

				d.vx *= d.drag;
				d.vy *= d.drag;

				d.theta += getRandomNumber( -0.5, 0.5 ) * d.wander;
				d.vx += Math.sin( d.theta ) * 0.5;
				d.vy += Math.cos( d.theta ) * 0.5;

				d.radius *= d.age;
				d.alive = d.radius > 0.5;

			}//move

			//Create a particle
			function spawn ( x, y ) {
				//Play around with these numbers to get different effects
				particle = {
					x: x,
					y: y,
					id: ID,
					alive: true,
					radius: getRandomNumber( circeRanges[0], circeRanges[1] ),
					wander: getRandomNumber( 1, 1.5 ),
					color: colors[ Math.round( getRandomNumber(0, colors.length-1)) ],
					drag: getRandomNumber( 0.2, 0.99 ),
					age: getRandomNumber( 0.92, 0.98 ),
					theta: getRandomNumber( 0,  2 * Math.PI ),
					force: getRandomNumber( forceRanges[0], forceRanges[1] )
				};

				ID += 1;

				particle.vx = Math.sin( particle.theta ) * particle.force;
				particle.vy = Math.cos( particle.theta ) * particle.force;

				particles.push( particle );
			}//spawn

			function getRandomNumber(start, end) {
			    return ((Math.random() * (end-start)) + start);
			}	

			///////////////////////////////////////////////////////////////////////////
			////////////// Functions to move through different blend modes ////////////
			///////////////////////////////////////////////////////////////////////////	

			var colorCounter = 0;
			function switchColors() {
				colorCounter = (colorCounter+1)%7;

				switch (colorCounter) {
				    case 0:
				        screenMode();
				        break;
				    case 1:
				        noMode();
				        break;
				    case 2:
				        screenModeRainbow();
				        break;
				    case 3:
				        screenModeGreen();
				        break;
				    case 4:
				        multiplyModeGreen();
				        break;
				    case 5:
				        multiplyModeRainbow();
				        break;
				    case 6:
				        multiplyModePurple();
				        break;
				}//switch colorCounter
			}//switchColors

			var loopColors = setInterval(switchColors, 3000);

			function screenMode() {
				colorMode = "screen";
				colors = ['#69D2E7', '#A7DBD8', '#E0E4CC', '#F38630', '#FA6900', '#FF4E50', '#F9D423'];
				d3.select("body").transition().duration(500).style("background", "#262626");
				d3.select(".colorStatus").text("mix-blend-mode: screen");
			}//screenMode

			function noMode() {
				colorMode = "none";
				colors = ['#69D2E7', '#A7DBD8', '#E0E4CC', '#F38630', '#FA6900', '#FF4E50', '#F9D423'];
				d3.select("body").transition().duration(500).style("background", "#262626");
				d3.select(".colorStatus").text("mix-blend-mode: none");
			}//noMode

			function screenModeRainbow() {
				colorMode = "screen";
				colors = ["#2c7bb6", "#00a6ca","#00ccbc","#90eb9d","#ffff8c","#f9d057","#f29e2e","#e76818","#d7191c"];
				d3.select("body").transition().duration(500).style("background", "#262626");
				d3.select(".colorStatus").text("mix-blend-mode: screen");
			}//multiplyModeRainbow

			function screenModeGreen() {
				colorMode = "screen";
				colors = ['#1B676B', '#519548', '#88C425', "#BEF202", "#EAFDE6"];
				d3.select("body").transition().duration(500).style("background", "#262626");
				d3.select(".colorStatus").text("mix-blend-mode: screen");
			}//screenModeGreen

			function multiplyModeGreen() {
				colorMode = "multiply";
				colors = ['#1B676B', '#519548', '#88C425', "#BEF202", "#EAFDE6"];
				d3.select("body").transition().duration(500).style("background", "white");
				d3.select(".colorStatus").text("mix-blend-mode: multiply");
			}//multiplyModeGreen

			function multiplyModeRainbow() {
				colorMode = "multiply";
				colors = ["#2c7bb6", "#00a6ca","#00ccbc","#90eb9d","#ffff8c","#f9d057","#f29e2e","#e76818","#d7191c"];
				d3.select("body").transition().duration(500).style("background", "white");
				d3.select(".colorStatus").text("mix-blend-mode: multiply");
			}//multiplyModeRainbow

			function multiplyModePurple() {
				colorMode = "multiply";
				colors = ['#490A3D', '#BD1550', '#E97F02', "#F8CA00", "#8A9B0F"];
				d3.select("body").transition().duration(500).style("background", "#F8E8E8");
				d3.select(".colorStatus").text("mix-blend-mode: multiply");
			}//multiplyModePurple


		</script>

	</body>
</html>