Created
March 7, 2016 02:28
-
-
Save anonymous/e25b4ea598a8c8af31cd to your computer and use it in GitHub Desktop.
Revisions
-
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,7 @@ Painting -------- http://jsdo.it/akm2/zAOw A [Pen](http://codepen.io/akm2/pen/BonIh) by [Akimitsu Hamamuro](http://codepen.io/akm2) on [CodePen](http://codepen.io/). [License](http://codepen.io/akm2/pen/BonIh/license). This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,2 @@ <div id="message">Drag mouse to paint.</div> <canvas id='c'></canvas> This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,440 @@ /** * requestAnimationFrame */ window.requestAnimationFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 60); }; })(); /** * Brush */ var Brush = (function() { /** * @constructor * @public */ function Brush(x, y, color, size, inkAmount) { this.x = x || 0; this.y = y || 0; if (color !== undefined) this.color = color; if (size !== undefined) this.size = size; if (inkAmount !== undefined) this.inkAmount = inkAmount; this._drops = []; this._resetTip(); } Brush.prototype = { _SPLASHING_BRUSH_SPEED: 75, x: 0, y: 0, color: '#000', size: 35, inkAmount: 7, splashing: true, dripping: true, _latestPos: null, _strokeId: null, _drops: null, isStroke: function() { return Boolean(this._strokeId); }, startStroke: function() { if (this.isStroke()) return; this._resetTip(); // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript this._strokeId = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r, v; r = Math.random() * 16 | 0; v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); }, endStroke: function() { this._strokeId = this._latestPos = null; }, render: function(ctx, x, y) { var isStroke = this.isStroke(), dx, dy, i, len; if (!this._latestPos) this._latestPos = {}; this._latestPos.x = this.x; this._latestPos.y = this.y; this.x = x; this.y = y; if (this._drops.length) { var drops = this._drops, drop, sizeSq = this.size * this.size; for (i = 0, len = drops.length; i < len; i++) { drop = drops[i]; dx = this.x - drop.x; dy = this.y - drop.y; if ( (isStroke && sizeSq > dx * dx + dy * dy && this._strokeId !== drop.strokeId) || drop.life <= 0 ) { drops.splice(i, 1); len--; i--; continue; } drop.render(ctx); } } if (isStroke) { var tip = this._tip, strokeId = this._strokeId, dist; dx = this.x - this._latestPos.x; dy = this.y - this._latestPos.y; dist = Math.sqrt(dx * dx + dy * dy); if (this.splashing && dist > this._SPLASHING_BRUSH_SPEED) { var maxNum = (dist - this._SPLASHING_BRUSH_SPEED) * 0.5 | 0, r, a, sr, sx, sy; ctx.save(); ctx.fillStyle = this.color; ctx.beginPath(); for (i = 0, len = maxNum * Math.random() | 0; i < len; i++) { r = (dist - 1) * Math.random() + 1; a = Math.PI * 2 * Math.random(); sr = 5 * Math.random(); sx = this.x + r * Math.sin(a); sy = this.y + r * Math.cos(a); ctx.moveTo(sx + sr, sy); ctx.arc(sx, sy, sr, 0, Math.PI * 2, false); } ctx.fill(); ctx.restore(); } else if (this.dripping && dist < this.inkAmount * 2 && Math.random() < 0.05) { this._drops.push(new Drop( this.x, this.y, (this.size + this.inkAmount) * 0.5 * ((0.25 - 0.1) * Math.random() + 0.1), this.color, this._strokeId )); } for (i = 0, len = tip.length; i < len; i++) { tip[i].render(ctx, dx, dy, dist); } } }, dispose: function() { this._tip.length = this._drops.length = 0; }, _resetTip: function() { var tip = this._tip = [], rad = this.size * 0.5, x0, y0, a0, x1, y1, a1, cv, sv, i, len; a1 = Math.PI * 2 * Math.random(); len = rad * rad * Math.PI / this.inkAmount | 0; if (len < 1) len = 1; for (i = 0; i < len; i++) { x0 = rad * Math.random(); y0 = x0 * 0.5; a0 = Math.PI * 2 * Math.random(); x1 = x0 * Math.sin(a0); y1 = y0 * Math.cos(a0); cv = Math.cos(a1); sv = Math.sin(a1); tip.push(new Hair( this.x + x1 * cv - y1 * sv, this.y + x1 * sv + y1 * cv, this.inkAmount, this.color )); } } }; /** * Hair * @private */ function Hair(x, y, inkAmount, color) { this.x = x || 0; this.y = y || 0; this.inkAmount = inkAmount; this.color = color; this._latestPos = { x: this.x, y: this.y }; } Hair.prototype = { x: 0, y: 0, inkAmount: 7, color: '#000', _latestPos: null, render: function(ctx, offsetX, offsetY, offsetLength) { this._latestPos.x = this.x; this._latestPos.y = this.y; this.x += offsetX; this.y += offsetY; var per = offsetLength ? this.inkAmount / offsetLength : 0; if (per > 1) per = 1; else if (per < 0) per = 0; ctx.save(); ctx.lineCap = ctx.lineJoin = 'round'; ctx.strokeStyle = this.color; ctx.lineWidth = this.inkAmount * per; ctx.beginPath(); ctx.moveTo(this._latestPos.x, this._latestPos.y); ctx.lineTo(this.x, this.y); ctx.stroke(); ctx.restore(); } }; /** * Drop * @private */ function Drop(x, y, size, color, strokeId) { this.x = x || 0; this.y = y || 0; this.size = size; this.color = color; this.strokeId = strokeId; this.life = this.size * 1.5; this._latestPos = { x: this.x, y: this.y }; } Drop.prototype = { x: 0, y: 0, size: 7, color: '#000', strokeId: null, life: 0, _latestPos: null, _xOffRatio: 0, render: function(ctx) { if (Math.random() < 0.03) { this._xOffRatio += 0.06 * Math.random() - 0.03; } else if (Math.random() < 0.1) { this._xOffRatio *= 0.003; } this._latestPos.x = this.x; this._latestPos.y = this.y; this.x += this.life * this._xOffRatio; this.y += (this.life * 0.5) * Math.random(); this.life -= (0.05 - 0.01) * Math.random() + 0.01; ctx.save(); ctx.lineCap = ctx.lineJoin = 'round'; ctx.strokeStyle = this.color; ctx.lineWidth = this.size + this.life * 0.3; ctx.beginPath(); ctx.moveTo(this._latestPos.x, this._latestPos.y); ctx.lineTo(this.x, this.y); ctx.stroke(); ctx.restore(); ctx.restore(); } }; return Brush; })(); // Initialize (function() { // Vars var canvas, context, centerX, centerY, mouseX = 0, mouseY = 0, isMouseDown = false, brush, gui, control, guiColorCtr, guiSizeCtr, guiIsRandColorCtr; // Event Listeners function resize(e) { canvas.width = window.innerWidth; canvas.height = window.innerHeight; centerX = canvas.width * 0.5; centerY = canvas.height * 0.5; context = canvas.getContext('2d'); control.clear(); } function mouseMove(e) { mouseX = e.clientX; mouseY = e.clientY; } function mouseDown(e) { mouseX = e.clientX; mouseY = e.clientY; if (control.isRandomColor) { brush.color = randomColor(); guiColorCtr.updateDisplay(); } if (control.isRandomSize) { brush.size = random(51, 5) | 0; guiSizeCtr.updateDisplay(); } brush.startStroke(mouseX, mouseY); } function mouseUp(e) { brush.endStroke(); } var touched = false; function touchMove(e) { var t = e.touches[0]; mouseX = t.clientX; mouseY = t.clientY; } function touchStart(e) { if (touched) return; touched = true; var t = e.touches[0]; mouseX = t.clientX; mouseY = t.clientY; if (control.isRandomColor) { brush.color = randomColor(); guiColorCtr.updateDisplay(); } if (control.isRandomSize) { brush.size = random(51, 5) | 0; guiSizeCtr.updateDisplay(); } brush.startStroke(mouseX, mouseY); } function touchEnd(e) { touched = false; brush.endStroke(); } // Helpers function randomColor() { var r = random(256) | 0, g = random(256) | 0, b = random(256) | 0; return 'rgb(' + r + ',' + g + ',' + b + ')'; } function random(max, min) { if (typeof max !== 'number') { return Math.random(); } else if (typeof min !== 'number') { min = 0; } return Math.random() * (max - min) + min; } // GUI Control control = { isRandomColor: true, isRandomSize: false, clear: function(e) { context.clearRect(0, 0, canvas.width, canvas.height); brush.dispose(); } }; // Init canvas = document.getElementById('c'); brush = new Brush(centerX, centerY, randomColor()); window.addEventListener('resize', resize, false); resize(null); canvas.addEventListener('mousemove', mouseMove, false); canvas.addEventListener('mousedown', mouseDown, false); canvas.addEventListener('mouseout', mouseUp, false); canvas.addEventListener('mouseup', mouseUp, false); canvas.addEventListener('touchmove', touchMove, false); canvas.addEventListener('touchstart', touchStart, false); canvas.addEventListener('touchcancel', touchEnd, false); canvas.addEventListener('touchend', touchEnd, false); // GUI gui = new dat.GUI(); guiColorCtr = gui.addColor(brush, 'color').name('Color').onChange(function() { control.isRandomColor = false; guiIsRandColorCtr.updateDisplay(); }); guiSizeCtr = gui.add(brush, 'size', 5, 50).name('Size'); gui.add(brush, 'inkAmount', 1, 30).name('Ink Amount'); gui.add(brush, 'splashing').name('Splashing'); gui.add(brush, 'dripping').name('Dripping'); guiIsRandColorCtr = gui.add(control, 'isRandomColor').name('Random Color'); gui.add(control, 'isRandomSize').name('Random Size'); gui.add(control, 'clear').name('Clear'); gui.close(); // Start Update var loop = function() { brush.render(context, mouseX, mouseY); requestAnimationFrame(loop); }; loop(); })(); This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1 @@ <script src="http://dat-gui.googlecode.com/git/build/dat.gui.min.js"></script> This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,36 @@ body { font-family: 'Anaheim', sans-serif; padding: 0; margin: 0; background: #f7f6f2; overflow: hidden; -webkit-user-select: none; -moz-user-select: none; -o-user-select: none; -ms-user-select: none; user-select: none; } canvas { position: absolute; top: 0; left: 0; z-index: 1; } #message { color: #e2e2de; font-size: 32px; text-align: center; letter-spacing: 2px; position: fixed; top: 50%; z-index: 0; width: 100%; margin-top: -0.5em; text-shadow: 0 -1px 0 #d3d3d1; } .dg.ac { z-index: 2; }