LOADING...

Preview

Pen ID
Unlock Campus Themeforest adv

 

Code

  
  
		
		
		
		

Neon

Click and drag to draw/write. Move sliders to adjust effects. Double click to clear screen. (No sliders in Firefox, sorry! & best in chrome...)

Open controls Close controls
Fork me on GitHub
CSS
@import url("https://fonts.googleapis.com/css?family=Carrois+Gothic|Nixie+One");

html, body {
    -webkit-font-smoothing: antialiased;
    font: normal 12px/14px "Carrois Gothic", sans-serif;
    width: 100%;
    height: 100%;
    margin: 0;
    overflow: hidden;
    color: #EEDBDF;
    text-shadow: 0 0 5px #EC637B,
        0 0 10px rgba(230, 161, 173, 0.41),
        0 0 500px #F36780;

    -webkit-user-select: none;
       -moz-user-select: none;
        -ms-user-select: none;
            user-select: none; 
}

html {
    background: url(http://neilcarpenter.com/demos/canvas/neon/dark_wall.png);
}

body {
    background: -moz-radial-gradient(center, ellipse cover, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.73) 100%);
    background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%, rgba(0, 0, 0, 0.04)), color-stop(100%, rgba(0, 0, 0, 0.73)));
    background: -webkit-radial-gradient(center, ellipse cover, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.73) 100%);
    background: -o-radial-gradient(center, ellipse cover, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.73) 100%);
    background: -ms-radial-gradient(center, ellipse cover, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.73) 100%);
    background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.73) 100%);
}

#canvas {
    z-index: 10;
    position: absolute;
    top: 0;
    left: 0;
}

h1 {
    font: normal 50px/50px "Nixie One", Helvetica, Arial;
    text-transform: uppercase;
    margin: 0;
    text-align: center;
    text-shadow: 0 0 20px #EC637B,
        0 0 10px rgba(230, 161, 173, 0.41),
        0 0 500px #F36780;

}

#controls {
    background: rgba(255, 255, 255, 0.05);
    position: fixed;
    top: 0;
    left: 20px;
    width: 250px;
    padding: 20px;
    z-index: 15;
    -webkit-transform-origin: top center;
       -moz-transform-origin: top center;
         -o-transform-origin: top center;
            transform-origin: top center;
    -webkit-transform: rotate(0deg);
       -moz-transform: rotate(0deg);
         -o-transform: rotate(0deg);
            transform: rotate(0deg);
    -webkit-transition: -webkit-transform .5s ease-in-out;
       -moz-transition:    -moz-transform .5s ease-in-out;
         -o-transition:      -o-transform .5s ease-in-out;
            transition:         transform .5s ease-in-out;
}

#controls.closed {
    -webkit-transform: rotate(-180deg);
       -moz-transform: rotate(-180deg);
         -o-transform: rotate(-180deg);
            transform: rotate(-180deg);
}

.controller {
    float: right;
    width: 150px;
}
.color {
    position: relative;
}
.color .controller {
        width: 120px;
        margin-right: 30px;
}

.color span {
        display: block;
        position: absolute;
        right: 0;
        top: 0;
        width: 15px;
        height: 15px;
}

.toggle-controls {
    position: absolute;
    display: block;
    height: 10px;
    background: rgba(255, 255, 255, 0.1);
    width: 290px;
    left: 0;
    text-align: center;
    padding: 3px 0 7px;
    text-decoration: none;
    color: white;
    text-shadow: none;
}

#close {
    bottom: -20px;
}

#open {
    top: -20px;
    -webkit-transform: rotate(180deg);
       -moz-transform: rotate(180deg);
         -o-transform: rotate(180deg);
            transform: rotate(180deg);
}
JS
/*
 *
 *
 * See demo page here:
 * http://neilcarpenter.com/labs/neon-writer
 *
 *
 */



// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
 
// requestAnimationFrame polyfill by Erik Möller
// fixes from Paul Irish and Tino Zijdel
 
(function() {
    var lastTime = 0;
    var vendors = ['ms', 'moz', 'webkit', 'o'];
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
                                   || window[vendors[x]+'CancelRequestAnimationFrame'];
    }
 
    if (!window.requestAnimationFrame)
        window.requestAnimationFrame = function(callback, element) {
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
            var id = window.setTimeout(function() { callback(currTime + timeToCall); },
              timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        };
 
    if (!window.cancelAnimationFrame)
        window.cancelAnimationFrame = function(id) {
            clearTimeout(id);
        };
}());

var NEON = {

  options: {
		lineWidth: 7,
		hue: 350
	},

	animation: null,

	canvas: null,
	context: null,

	winWidth: window.innerWidth,
	winHeight: window.innerHeight,

	mouse: { x: -1000, y: -1000, down: false },
	mousePrev: { x: -1000, y: -1000 },

	canvii: [],

	mousePaths : [],
	mousePathsCounter : 0,

	flickerInit: false,
	timer: null,

	init: function () {
		this.canvas = document.getElementById( 'canvas' );
		this.context = canvas.getContext( '2d' );
		this.canvas.width = this.winWidth;
		this.canvas.height = this.winHeight;

		this.canvas.addEventListener('mousemove', this.mouseMove, false);
		this.canvas.addEventListener('mousedown', this.mouseDown, false);
		this.canvas.addEventListener('mouseup', this.mouseUp, false);
		this.canvas.addEventListener('mouseout', this.mouseOut, false);
		this.canvas.addEventListener('dblclick', this.mouseDbl, false);

		this.draw();

		window.onresize = function () {
			NEON.clearAll();

			NEON.winWidth = window.innerWidth;
			NEON.winHeight = window.innerHeight;
			NEON.canvas.width = NEON.winWidth;
			NEON.canvas.height = NEON.winHeight;
		};
	},

	drawLines: function () {
		if (!this.mouse.down) {
			return;
		}

		var deets = {
				mouseX: this.mouse.x,
				mouseY: this.mouse.y,
				hue: this.options.hue,
				lineWidth: this.options.lineWidth
			};

		// drawing in real-time
		var ctx = this.context;

		ctx.globalCompositeOperation = 'destination-over';

		ctx.lineCap = 'round';
		ctx.lineJoin = 'round';
		ctx.lineWidth = this.options.lineWidth;

		ctx.shadowOffsetX = 5;
		ctx.shadowOffsetY = 5;
		ctx.shadowBlur = 10;
		ctx.shadowColor = 'hsla(0, 0%, 0%, 0.7)';

		ctx.beginPath();
		ctx.strokeStyle = 'hsla(' + this.options.hue + ', 100%, 50%, 1)';
		ctx.moveTo(this.mousePrev.x, this.mousePrev.y);
		ctx.lineTo(this.mouse.x, this.mouse.y);
		ctx.stroke();

		ctx.shadowOffsetX = 0;
		ctx.shadowOffsetY = 0;
		ctx.shadowBlur = 30;
		ctx.shadowColor = 'hsla(' + this.options.hue + ', 100%, 50%, 0.8)';

		ctx.beginPath();
		ctx.moveTo(this.mousePrev.x, this.mousePrev.y);
		ctx.lineTo(this.mouse.x, this.mouse.y);
		ctx.stroke();

		ctx.shadowBlur = 200;
		ctx.shadowColor = 'hsla(' + this.options.hue + ', 80%, 70%, 0.9)';

		ctx.beginPath();
		ctx.moveTo(this.mousePrev.x, this.mousePrev.y);
		ctx.lineTo(this.mouse.x, this.mouse.y);
		ctx.stroke();

		// save mouse co-ords for this line
		this.mousePaths[this.mousePathsCounter].push(deets);
	},

	// this isn't a great way to do anything, too many canvii!
	drawNewCanvas: function (index) {
		var points = this.mousePaths[index],
			pointsLen = points.length,
			c = document.createElement('canvas'),
			ctx = c.getContext('2d');

		c.width = NEON.winWidth;
		c.height = NEON.winHeight;
		c.style.position = 'absolute';
		c.style.top = 0;
		c.style.left = 0;
		c.style.zIndex = 0;
		// c.style.cssText += '-webkit-filter: saturate(1.5)';

		c.dataset.canvas = index;
		c.className = 'dummy';

		ctx.lineCap = 'round';
		ctx.lineJoin = 'round';
		ctx.lineWidth = points[0].lineWidth;
		ctx.globalCompositeOperation = 'destination-over';

		ctx.shadowOffsetX = 5;
		ctx.shadowOffsetY = 5;
		ctx.shadowBlur = 10;
		ctx.shadowColor = 'hsla(0, 0%, 0%, 0.7)';
		
		ctx.strokeStyle = 'hsla(' + points[0].hue + ', 100%, 50%, 1)';
		ctx.beginPath();
		for (var i = 0; i < pointsLen; i++) {
			if (i === 0) {
				ctx.moveTo((points[i].mouseX), (points[i].mouseY));
			}
			else {
				ctx.lineTo((points[i].mouseX), (points[i].mouseY));
			}
		}
		ctx.stroke();

		ctx.shadowOffsetX = 0;
		ctx.shadowOffsetY = 0;
		ctx.shadowBlur = 30;
		ctx.shadowColor = 'hsla(' + points[0].hue + ', 100%, 50%, 0.8)';
		ctx.beginPath();
		for (var i = 0; i < pointsLen; i++) {
			if (i === 0) {
				ctx.moveTo((points[i].mouseX), (points[i].mouseY));
			}
			else {
				ctx.lineTo((points[i].mouseX), (points[i].mouseY));
			}
		}
		ctx.stroke();

		ctx.shadowBlur = 200;
		ctx.shadowColor = 'hsla(' + points[0].hue + ', 80%, 70%, 0.9)';
		ctx.beginPath();
		for (var i = 0; i < pointsLen; i++) {
			if (i === 0) {
				ctx.moveTo((points[i].mouseX), (points[i].mouseY));
			}
			else {
				ctx.lineTo((points[i].mouseX), (points[i].mouseY));
			}
		}
		ctx.stroke();

		document.body.appendChild(c);

		this.canvii.push(c);

	},

	draw: function () {
		this.animation = requestAnimationFrame( function(){ NEON.draw(); } );

		this.drawLines();

		this.mousePrev.x = this.mouse.x;
		this.mousePrev.y = this.mouse.y;
	},

	flicker: function() {
		var wait = NEON.randomFromInterval(0, 2000),
			flickersCount = NEON.randomFromInterval(10, 30),
			canviiLen = NEON.canvii.length,
			randomCanvasIndex = NEON.randomFromInterval(0, (canviiLen - 1)),
			canvas = NEON.canvii[randomCanvasIndex],
			ctx = canvas.getContext('2d'),
			points = NEON.mousePaths[randomCanvasIndex],
			pointsLen = points.length,
			hue = points[0].hue,
			lineWidth = points[0].lineWidth;

		ctx.lineCap = 'round';
		ctx.lineJoin = 'round';

		if (flickersCount % 2 !== 0) {
			flickersCount -= 1;
		}

		function flick() {
			if (flickersCount === 0) {
				return;
			}
			else if (flickersCount % 2 !== 0) {
				NEON.repaint(ctx, points, pointsLen, hue, lineWidth, false);
			}
			else {
				NEON.repaint(ctx, points, pointsLen, hue, lineWidth, true);
			}
			flickersCount -= 1;
			setTimeout(flick, 20);
		}
		flick();

		NEON.timer = setTimeout(NEON.flicker, wait);
	},

	repaint: function(ctx, points, pointsLen, hue, lineWidth, faded) {
		ctx.clearRect(0, 0, NEON.winWidth, NEON.winHeight);

		ctx.lineWidth = lineWidth;
		ctx.globalCompositeOperation = 'destination-over';

		ctx.shadowOffsetX = 5;
		ctx.shadowOffsetY = 5;
		ctx.shadowBlur = 10;
		ctx.shadowColor = 'hsla(0, 0%, 0%, 0.7)';
		
		if (faded) {
			ctx.strokeStyle = 'hsla(' + hue + ', 10%, 20%, 1)';
		}
		else {
			ctx.strokeStyle = 'hsla(' + hue + ', 100%, 50%, 1)';
		}

		ctx.beginPath();
		for (var i = 0; i < pointsLen; i++) {
			if (i === 0) {
				ctx.moveTo((points[i].mouseX), (points[i].mouseY));
			}
			else {
				ctx.lineTo((points[i].mouseX), (points[i].mouseY));
			}
		}
		ctx.stroke();

		ctx.shadowOffsetX = 0;
		ctx.shadowOffsetY = 0;
		ctx.shadowBlur = 30;

		if (faded) {
			ctx.shadowColor = 'hsla(' + hue + ', 10%, 10%, 0.8)';
		}
		else {
			ctx.shadowColor = 'hsla(' + hue + ', 100%, 50%, 0.8)';
		}

		ctx.beginPath();
		for (var i = 0; i < pointsLen; i++) {
			if (i === 0) {
				ctx.moveTo((points[i].mouseX), (points[i].mouseY));
			}
			else {
				ctx.lineTo((points[i].mouseX), (points[i].mouseY));
			}
		}
		ctx.stroke();

		ctx.shadowBlur = 200;

		if (faded) {
			ctx.shadowColor = 'hsla(' + hue + ', 5%, 7%, 0.9)';
		}
		else {
			ctx.shadowColor = 'hsla(' + hue + ', 80%, 70%, 0.9)';
		}

		ctx.beginPath();
		for (var i = 0; i < pointsLen; i++) {
			if (i === 0) {
				ctx.moveTo((points[i].mouseX), (points[i].mouseY));
			}
			else {
				ctx.lineTo((points[i].mouseX), (points[i].mouseY));
			}
		}
		ctx.stroke();
	},

	randomFromInterval: function(from, to) {
		return Math.floor(Math.random()*(to-from+1)+from);
	},

	clearDrawingSurface: function() {
		this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
	},

	clearAll: function() {
		for (var i = 0; i < this.canvii.length; i++) {
			NEON.canvii[i].parentNode.removeChild(NEON.canvii[i]);
		}
		NEON.canvii.length = 0;
		NEON.mousePathsCounter = 0;
		NEON.flickerInit = false;
		clearTimeout(NEON.timer);
	},

	mouseMove: function (e) {
		NEON.mouse.x = e.offsetX || (e.layerX - NEON.canvas.offsetLeft);
		NEON.mouse.y = e.offsetY || (e.layerY - NEON.canvas.offsetTop);
	},

	mouseDown: function () {
		NEON.mousePaths[NEON.mousePathsCounter] = [];
		NEON.mouse.down = true;
	},

	mouseUp: function () {
		NEON.clearDrawingSurface();
		NEON.drawNewCanvas(NEON.mousePathsCounter);
		NEON.mousePathsCounter += 1;
		NEON.mouse.down = false;

		if (!NEON.flickerInit) {
			setTimeout(NEON.flicker, 2000);
			NEON.flickerInit = true;
		}
	},

	mouseOut: function () {
		NEON.mouse.down = false;
	},

	mouseDbl: function () {
		NEON.clearAll();
	}

};

function eventListenerz() {
	var inputs = document.getElementsByClassName('controller'),
		colorSpan = document.getElementById('color-indicator');

	colorSpan.style.backgroundColor = 'hsl(' + NEON.options.hue + ', 100%, 50%)';	

	function onChange() {
		var name = this.name,
			value = this.value,
			max = this.getAttribute('max');

		value = +value;

		if (value > max) {
			value = max;
			this.value = max;
		}

		NEON.options[name] = value;

		if (this.name === 'hue') {
			var colorSpan = document.getElementById('color-indicator');
			colorSpan.style.backgroundColor = 'hsl(' + NEON.options.hue + ', 100%, 50%)';
		}

	}

	for (var i = 0; i < inputs.length; i++) {
		inputs[i].addEventListener('change', onChange, false);
	}

	var controlToggles = document.getElementsByClassName('toggle-controls'),
		controls = document.getElementById('controls');

	function toggleControls(e) {
		e.preventDefault();
		controls.className = controls.className === 'closed' ? '' : 'closed';
	}

	for (var j = 0; j < 2; j++) {
		controlToggles[j].addEventListener('click', toggleControls, false);
	}

}

window.onload = function() {

	NEON.init();

	eventListenerz();

};
Host Instantly Drag and Drop Website Builder

 

Description

Trying to recreate this: http://codepen.io/neilcarpenter/pen/zFlay, but with canvas, allowing user to draw in flickery-neon lights. Performance isn't great, need to work on that.
Term
Mon, 11/27/2017 - 22:00

Related Codes

Pen ID
Pen ID
Pen ID