{"id":188,"date":"2015-06-12T00:00:10","date_gmt":"2015-06-12T00:00:10","guid":{"rendered":"http:\/\/bloodforge.com\/?p=188"},"modified":"2020-02-20T05:02:36","modified_gmt":"2020-02-20T05:02:36","slug":"the-jquery-bloodforge-smoke-effect","status":"publish","type":"post","link":"https:\/\/bloodforge.azurewebsites.net\/index.php\/2015\/06\/12\/the-jquery-bloodforge-smoke-effect\/","title":{"rendered":"The jQuery Bloodforge Smoke Effect"},"content":{"rendered":"\n<script src=\"https:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/3.4.1\/jquery.min.js\"><\/script>\n<fieldset><legend>Adjust the smoke in this post header<\/legend>\n<div class=\"smoke-adjust\"><label for=\"smoke-color\">Color<\/label> <input id=\"smoke-color\" type=\"color\" value=\"#000000\"><\/div>\n<div class=\"smoke-adjust\"><label for=\"smoke-opacity\">Opacity<\/label> <input id=\"smoke-opacity\" max=\"1\" min=\"0\" step=\"0.01\" type=\"range\" value=\"0.2\"><\/div>\n<div class=\"smoke-adjust\"><label for=\"smoke-speed\">Speed<\/label> <input id=\"smoke-speed\" max=\"200\" min=\"1\" step=\"1\" type=\"range\" value=\"50\"><\/div>\n<div class=\"smoke-adjust\"><label for=\"smoke-size\">Particle Size<\/label> <input id=\"smoke-size\" max=\"500\" min=\"10\" step=\"1\" type=\"range\" value=\"150\"><\/div>\n<div class=\"smoke-adjust\"><label for=\"smoke-density\">Density<\/label> <input id=\"smoke-density\" max=\"20\" min=\"1\" step=\"1\" type=\"range\" value=\"10\"><\/div>\n<\/fieldset>\n<script>\n\/\/ <![CDATA[\n\/*\nBloodforge Smoke Effect v1.4\nCopyright (c) 2017 Filip Stanek (http:\/\/bloodforge.com)\nBased off code written by Johny Cornwell (http:\/\/www.blog.jonnycornwell.com\/)\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and\/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*\/\n\n\/\/ A function to create a particle object.\nfunction Particle(context, canvasWidth, canvasHeight) {\n\n    \/\/ Set the initial x and y positions\n    this._x = 0;\n    this._y = 0;\n\n    \/\/ Set the initial velocity\n    this._xVelocity = 50;\n    this._yVelocity = 50;\n\n    \/\/ Store the context which will be used to draw the particle\n    this._context = context;\n\n    this._innerColor = 'rgba(0, 0, 0, 0.2)';\n    this._outerColor = 'rgba(0, 0, 0, 0)';\n\n    this._radius = 128;\n\n    \/\/ Set the dimensions of the canvas as variables so they can be used.\n    this._canvasWidth = canvasWidth;\n    this._canvasHeight = canvasHeight;\n}\n\n\/\/ The function to draw the particle on the canvas.\nParticle.prototype.Draw = function () {\n    var gradient = this._context.createRadialGradient(this._x, this._y, 5, this._x, this._y, this._radius);\n    gradient.addColorStop(0, this._innerColor);\n    gradient.addColorStop(1, this._outerColor);\n\n    this._context.beginPath();\n    this._context.arc(this._x, this._y, this._radius, 0, 2 * Math.PI);\n    this._context.fillStyle = gradient;\n    this._context.fill();\n    this._context.closePath();\n};\n\n\/\/ Update the particle.\nParticle.prototype.Update = function (travelPercentage) {\n    \/\/ Update the position of the particle with the addition of the velocity.\n    this._x += (this._xVelocity * travelPercentage);\n    this._y += (this._yVelocity * travelPercentage);\n\n    \/\/ Check if has crossed the right edge\n    if (this._x >= this._canvasWidth) {\n        this._xVelocity = -this._xVelocity;\n        this._x = this._canvasWidth;\n    }\n    \/\/ Check if has crossed the left edge\n    else if (this._x <= 0) {\n        this._xVelocity = -this._xVelocity;\n        this._x = 0;\n    }\n\n    \/\/ Check if has crossed the bottom edge\n    if (this._y >= this._canvasHeight) {\n        this._yVelocity = -this._yVelocity;\n        this._y = this._canvasHeight;\n    }\n\n    \/\/ Check if has crossed the top edge\n    else if (this._y <= 0) {\n        this._yVelocity = -this._yVelocity;\n        this._y = 0;\n    }\n    this._x = Math.round(this._x);\n    this._y = Math.round(this._y);\n};\n\n\/\/ A function to set the position of the particle.\nParticle.prototype.SetPosition = function (x, y) {\n    this._x = x;\n    this._y = y;\n};\n\n\/\/ Function to set the velocity.\nParticle.prototype.SetVelocity = function (v) {\n    this._xVelocity = this.GenerateRandom(-v, v);\n    this._yVelocity = this.GenerateRandom(-v, v);\n};\n\nParticle.prototype.SetRadius = function (r) {\n    this._radius = r;\n};\n\nParticle.prototype.SetColor = function (rgb, a) {\n    this._innerColor = 'rgba(' + rgb[0] + ', ' + rgb[1] + ', ' + rgb[2] + ', ' + a + ')';\n    this._outerColor = 'rgba(' + rgb[0] + ', ' + rgb[1] + ', ' + rgb[2] + ', ' + 0 + ')';\n};\n\nParticle.prototype.GenerateRandom = function (min, max) {\n    return Math.random() * (max - min) + min;\n};\n\n(function ($) {\n\n    var PLUGIN_NAME = 'SmokeEffect';\n\n    var colorToRGBA = function (color) {\n        var cvs, ctx;\n        cvs = document.createElement('canvas');\n        cvs.height = 1;\n        cvs.width = 1;\n        ctx = cvs.getContext('2d');\n        ctx.fillStyle = color;\n        ctx.fillRect(0, 0, 1, 1);\n        return ctx.getImageData(0, 0, 1, 1).data;\n    };\n\n    var calculateParticleCount = function (width, height, density, radius) {\n        var totalPixels = width * height;\n        var imgPixels = radius * radius * Math.PI;\n        var areaRatio = totalPixels \/ imgPixels;\n        return Math.ceil(density * areaRatio);\n    };\n\n    var fnAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || function (fn) {\n        return setTimeout(fn, 15);\n    };\n\n    var methods = {\n\n        init: function (options) {\n\n            return this.each(function () {\n                var $container = $(this);\n\n                var settings = $.extend({\n                    color: 'black',\n                    opacity: 0.2,\n                    density: 10,\n                    maximumVelocity: 50,\n                    particleRadius: 150\n                }, options);\n\n                var bInitialized = $container.data(PLUGIN_NAME);\n                if (!bInitialized) {\n\n                    var canvas;\n\n                    settings.width = $container.outerWidth();\n                    settings.height = $container.outerHeight();\n\n                    if ($container.prop('tagName') == 'CANVAS') {\n                        canvas = $container[0];\n                        settings.isCanvas = true;\n                    }\n                    else {\n                        canvas = document.createElement('CANVAS');\n                        canvas.width = settings.width;\n                        canvas.height = settings.height;\n                        settings.isCanvas = false;\n                    }\n\n                    if (canvas) if(canvas.getContext) {\n                        settings.context = canvas.getContext('2d');\n                        settings.color = colorToRGBA(settings.color);\n                    }\n                    else {\n                        $.error('Cannot create SmokeEffect because the browser lacks support');\n                    }\n                    $container.data(PLUGIN_NAME, settings);\n                    $container.SmokeEffect('createParticles');\n\n                    \/\/ set up animation loop\n                    var lastFrame = 0;\n                    var loop = function () {\n                        var now = new Date();\n                        var deltaT = now - lastFrame;\n\n                        \/\/ only do this at 15FPS, at most\n                        if (deltaT > 66) {\n                            $container.SmokeEffect('update', now - lastFrame);\n                            lastFrame = now;\n                        }\n\n                        fnAnimationFrame(loop);\n                    };\n                    loop(lastFrame);\n                }\n            });\n        },\n\n        createParticles: function () {\n            return this.each(function () {\n                var $container = $(this);\n                var settings = $container.data(PLUGIN_NAME);\n                if (settings) if(settings.context) {\n                    var particles = settings.particles || [];\n\n                    \/\/ Create the particles and set their initial positions and velocities\n                    var particleCount = calculateParticleCount(settings.width, settings.height, settings.density, settings.particleRadius);\n\n                    while (particles.length > particleCount) {\n                        settings.particles.pop();\n                    }\n\n                    while (particles.length < particleCount) {\n                        var particle = new Particle(settings.context, settings.width, settings.height);\n\n                        \/\/ Set particle properties\n                        particle.SetPosition(particle.GenerateRandom(0, settings.width), particle.GenerateRandom(0, settings.height));\n                        particle.SetVelocity(settings.maximumVelocity);\n                        particle.SetRadius(settings.particleRadius);\n                        particle.SetColor(settings.color, settings.opacity);\n\n                        particles.push(particle);\n                    }\n                    settings.particles = particles;\n\n                    $container.data(PLUGIN_NAME, settings);\n                }\n            });\n        },\n\n        update: function (deltaT) {\n            \/\/ Update the scene\n            var settings = $(this).data(PLUGIN_NAME);\n\n            if (settings) if(settings.context) {\n                var $container = $(this);\n                \n                var width = $container.outerWidth();\n                var height = $container.outerHeight();\n                if (settings.width != width || settings.height != height) {\n                    $container.SmokeEffect('resize');\n                    return;\n                }\n\n                \/\/ Clear the drawing surface\n                settings.context.clearRect(0, 0, settings.width, settings.height);\n\n                var travelPercentage = Math.min(deltaT \/ 1000, 1);\n\n                settings.particles.forEach(function (particle) {\n                    particle.Update(travelPercentage);\n                    particle.Draw();\n                });\n\n                if (!settings.isCanvas) {\n                    var img = new Image();\n                    img.onload = function () {\n                        $container.css('backgroundImage', 'url(' + this.src + ')');\n                    };\n                    img.src = settings.context.canvas.toDataURL();\n                }\n            }\n        },\n\n        resize: function () {\n            return this.each(function () {\n                var $container = $(this);\n                var settings = $container.data(PLUGIN_NAME);\n                settings.width = $container.outerWidth();\n                settings.height = $container.outerHeight();\n                settings.particles = [];\n                if (settings.isCanvas) {\n                    $container.get(0).width = settings.width;\n                    $container.get(0).height = settings.height;\n                }\n                else {\n                    var canvas = document.createElement('CANVAS');\n                    canvas.width = settings.width;\n                    canvas.height = settings.height;\n                    if (canvas) \n                      if (canvas.getContext) {\n                        settings.context = canvas.getContext('2d');\n                      }\n                }\n                $container.data(PLUGIN_NAME, settings);\n                $container.SmokeEffect('createParticles');\n            });\n        },\n\n        option: function (sName, vValue) {\n            var $container = $(this);\n            var settings = $container.data(PLUGIN_NAME);\n            if (typeof (sName) == \"string\") {\n                if (vValue == undefined) return settings[sName];\t\/\/ getter of option\n\n                settings[sName] = vValue;\t\/\/ setter of option\n            }\n            else {\n                settings = $.extend(settings, sName);\n            }\n\n            switch (sName) {\n                case \"maximumVelocity\":\n                    settings.particles.forEach(function (particle) {\n                        particle.SetVelocity(vValue);\n                    });\n                    break;\n                case \"particleRadius\":\n                    settings.particles.forEach(function (particle) {\n                        particle.SetRadius(vValue);\n                    });\n                    break;\n                case \"color\":\n                    settings.color = colorToRGBA(vValue);\n                    settings.particles.forEach(function (particle) {\n                        particle.SetColor(settings.color, settings.opacity);\n                    });\n                    break;\n                case \"opacity\":\n                    settings.particles.forEach(function (particle) {\n                        particle.SetColor(settings.color, vValue);\n                    });\n                    break;\n                case \"density\":\n                    $container.SmokeEffect('createParticles');\n                    break;\n            }\n\n            $container.data(PLUGIN_NAME, settings);\n        }\n    };\n\n    $.fn.SmokeEffect = function (method) {\n        \/\/ Method calling logic\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        }\n        else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        }\n        else {\n            $.error(\"Method '\" + method + \"' does not exist on plugin '\" + PLUGIN_NAME + \"'\");\n        }\n    };\n}(jQuery));\n\nvar seInterval = setInterval(function() {\nvar $se = $('figure.post_thum');\nif($se.outerWidth() > 0) {\n$se.html('<canvas id=\"header-canvas\" style=\"width: 100%; height: 100%;\" width=\"' + $se.outerWidth() + '\" height=\"' + $se.outerHeight() + '\" ><\/canvas>');\n$('.post-header').css('backgroundImage', 'none');\n$('#header-canvas').SmokeEffect();\n$('#smoke-color').change(function() {\n$('#header-canvas').SmokeEffect('option', 'color', $(this).val());\n$('#code-color').text($(this).val());\n});\n$('#smoke-opacity').change(function() {\n$('#header-canvas').SmokeEffect('option', 'opacity', $(this).val());\n$('#code-opacity').text($(this).val());\n});\n$('#smoke-speed').change(function() {\n$('#header-canvas').SmokeEffect('option', 'maximumVelocity', $(this).val());\n$('#code-speed').text($(this).val());\n});\n$('#smoke-size').change(function() {\n$('#header-canvas').SmokeEffect('option', 'particleRadius', $(this).val());\n$('#code-size').text($(this).val());\n});\n$('#smoke-density').change(function() {\n$('#header-canvas').SmokeEffect('option', 'density', $(this).val());\n$('#code-density').text($(this).val());\n});\nclearInterval(seInterval);\n}\n}, 100);\n\/\/ ]]>\n<\/script>\n\n\n\n<p> The following code represents the current settings of the header of this post. As you change the values above, the code below will update. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$('.post-header').SmokeEffect({\n    color: 'black',\n    opacity: 0.2,\n    maximumVelocity: 1,\n    particleRadius: 128\n    density: 10\n});<\/code><\/pre>\n\n\n\n<h4>Source Code<\/h4>\n\n\n\n<p>The code is located on Github at&nbsp;<a href=\"https:\/\/github.com\/murst\/Bloodforge-Smoke-Effect\">https:\/\/github.com\/murst\/Bloodforge-Smoke-Effect\ufeff<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Adjust the smoke in this post header Color Opacity Speed Particle Size Density The following code represents the current settings of the header of this post. As you change the values above, the code below will update. Source Code The code is located on Github at&nbsp;https:\/\/github.com\/murst\/Bloodforge-Smoke-Effect\ufeff<\/p>\n","protected":false},"author":1,"featured_media":205,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[3],"tags":[],"_links":{"self":[{"href":"https:\/\/bloodforge.azurewebsites.net\/index.php\/wp-json\/wp\/v2\/posts\/188"}],"collection":[{"href":"https:\/\/bloodforge.azurewebsites.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bloodforge.azurewebsites.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bloodforge.azurewebsites.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bloodforge.azurewebsites.net\/index.php\/wp-json\/wp\/v2\/comments?post=188"}],"version-history":[{"count":14,"href":"https:\/\/bloodforge.azurewebsites.net\/index.php\/wp-json\/wp\/v2\/posts\/188\/revisions"}],"predecessor-version":[{"id":217,"href":"https:\/\/bloodforge.azurewebsites.net\/index.php\/wp-json\/wp\/v2\/posts\/188\/revisions\/217"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/bloodforge.azurewebsites.net\/index.php\/wp-json\/wp\/v2\/media\/205"}],"wp:attachment":[{"href":"https:\/\/bloodforge.azurewebsites.net\/index.php\/wp-json\/wp\/v2\/media?parent=188"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bloodforge.azurewebsites.net\/index.php\/wp-json\/wp\/v2\/categories?post=188"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bloodforge.azurewebsites.net\/index.php\/wp-json\/wp\/v2\/tags?post=188"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}