<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<!DOCTYPE html><html lang='en' class=''>
<head><script src='//production-assets.codepen.io/assets/editor/live/console_runner-079c09a0e3b9ff743e39ee2d5637b9216b3545af0de366d4b9aad9dc87e26bfd.js'></script><script src='//production-assets.codepen.io/assets/editor/live/events_runner-73716630c22bbc8cff4bd0f07b135f00a0bdc5d14629260c3ec49e5606f98fdd.js'></script><script src='//production-assets.codepen.io/assets/editor/live/css_live_reload_init-2c0dc5167d60a5af3ee189d570b1835129687ea2a61bee3513dee3a50c115a77.js'></script><meta charset='UTF-8'><meta name="robots" content="noindex"><link rel="shortcut icon" type="image/x-icon" href="//production-assets.codepen.io/assets/favicon/favicon-8ea04875e70c4b0bb41da869e81236e54394d63638a1ef12fa558a4a835f1164.ico" /><link rel="mask-icon" type="" href="//production-assets.codepen.io/assets/favicon/logo-pin-f2d2b6d2c61838f7e76325261b7195c27224080bc099486ddd6dccb469b8e8e6.svg" color="#111" /><link rel="canonical" href="https://codepen.io/malipetek/pen/oGqLdZ" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style class="cp-pen-styles">html, body{
width: 100%;
height: 100%;
margin: 0;
}
.devsite-site-logo{
position: fixed;
z-index: 1;
left: 100px;
top: 20px;
}</style></head><body>
<canvas id="canvas">
</canvas>
<img src="https://firebase.google.com/_static/39ff68b8e1/images/firebase/lockup.png" class="devsite-site-logo" alt="Firebase">
<script src='//production-assets.codepen.io/assets/common/stopExecutionOnTimeout-b2a7b3fe212eaa732349046d8416e00a9dec26eb7fd347590fbced3ab38af52e.js'></script><script src='https://code.jquery.com/jquery-3.2.1.min.js'></script><script src='https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.0.0-beta.7/fabric.min.js'></script><script src='https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.12.0/matter.min.js'></script><script src='https://rawgit.com/brian3kb/graham_scan_js/master/graham_scan.min.js'></script><script src='https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.5/dat.gui.min.js'></script>
<script >var gui = new dat.GUI();
function paramsC(){
this.circleSizeMin = 1;
this.circleSizeRandom = 5;
this.visibleCircleSizeRatio = 1;
this.fireGradient0 = [255, 100, 0, 0];
this.fireGradient1 = [255, 203, 43, 1];
this.particleColor = '#c84600';
this.outLineGroupSize = 15;
this.flameFadeAway = 0.2;
this.shuffleFlameShape = false;
this.gradientStop0 = 0;
this.gradientStop1 = 20;
this.particleFadeAway = 0.01;
this.particleFadeAwayRandomness = 0.02;
this.backgroundColor = '#1e88e5';
}
var params = new paramsC();
gui.add(params, 'circleSizeMin', 0, 10);
gui.add(params, 'circleSizeRandom', 0, 10);
gui.add(params, 'visibleCircleSizeRatio', 0, 2);
gui.addColor(params, 'particleColor');
gui.add(params, 'particleFadeAway', 0.001, 0.1);
gui.add(params, 'particleFadeAwayRandomness', 0.001, 0.1);
gui.add(params, 'outLineGroupSize', 3, 100);
gui.add(params, 'flameFadeAway', 0.05, 0.8);
gui.add(params, 'shuffleFlameShape');
gui.addColor(params, 'fireGradient0');
gui.addColor(params, 'fireGradient1');
gui.add(params, 'gradientStop0', -100, 100);
gui.add(params, 'gradientStop1', -100, 100);
gui.addColor(params, 'backgroundColor').onChange((color) =>{
canvas.setBackgroundColor(color);
});
function rcl(){
return "#"+((1<<24)*Math.random()|0).toString(16);
}
function shuffleArray(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
const fireParticles = [];
const firePolygons = [];
function keepTrackArray(array){
this.array = array;
}
keepTrackArray.prototype.add = function(el){
this.array.push(el);
}
keepTrackArray.prototype.remove = function(el){
this.array.forEach((e,i)=> {if (e == el) this.array.splice(i,1);});
}
var cvsEl = document.getElementById('canvas');
var vw = window.innerWidth / 100;
var vh = window.innerHeight / 100;
cvsEl.width = window.innerWidth;
cvsEl.height = window.innerHeight;
fabric.Object.prototype.matterAction = ()=>{};
fabric.Object.prototype.matter = {};
fabric.Point.prototype.matterAction = ()=>{};
fabric.Point.prototype.matter = {};
const canvas = new fabric.Canvas(cvsEl);
canvas.selection = false;
canvas.objectCaching = false;
canvas.renderOnAddRemove = false;
canvas.setBackgroundColor(params.backgroundColor);
let Engine = Matter.Engine,
World = Matter.World,
Bodies = Matter.Bodies;
const engine = Engine.create({ enableSleeping: false });
const world = engine.world;
world.gravity.x = 0;
world.gravity.y = -0.7;
World.add(world, [
Bodies.rectangle(50*vw, -75, 100*vw, 150, { isStatic: true, friction: 0.01 }),
Bodies.rectangle(50*vw, 100*vh + 75, 100*vw, 150, { isStatic: true, friction: 0.01 }),
Bodies.rectangle(-75, 50*vh, 150, 100*vh, { isStatic: true, friction: 0.01 }),
Bodies.rectangle(100*vw + 75, 50*vh, 150, 100*vh, { isStatic: true, friction: 0.01 }),
]);
const mouse = Matter.Mouse.create($('.upper-canvas').get(0));
const mouseConstraint = Matter.MouseConstraint.create(engine, {
mouse,
stiffness: 0.5,
});
//addToWorld({type: 'rect', x: 10*vw, y: 30*vh, w:100, h: 20, fill: '#ddd'});
function addToWorld({type, x, y, w, h, r, fill, stroke, action}){
switch(type){
case 'rect':
const rect = new fabric.Rect({
left: x,
top: y,
width: w,
height: h,
stroke,fill
});
canvas.add(rect);
rect.matter = Bodies.rectangle(x, y, w, h, { isStatic: true });
rect.matterAction = action;
World.add(world, rect.matter);
break;
case 'circ':
const circle = new fabric.Circle({
selectable: false,
left: x-r,
top: y-r,
width: w,
height: h,
radius: r * params.visibleCircleSizeRatio,
stroke,fill
});
canvas.add(circle);
circle.matter = Bodies.circle(x, y, r, { restitution: 0.5 });
circle.matterAction = action;
World.add(world, circle.matter);
break;
}
}
function removeFromWorld(e){
World.remove(world, e.matter);
canvas.remove(e);
}
let fireX = 45*vw;
let fireY = 90*vh;
function render() {
canvas._objects.forEach((e) => {
if(e.type == 'polyline') {
e.set({opacity: e.opacity - params.flameFadeAway});
if(e.opacity <= 0.1) canvas.remove(e);
}
if(e.type == 'circle'){
e.matterAction(e);
}
});
let pointsArray = canvas._objects.map((e)=>{
if(e.type == 'polyline') return;
return {x: e.left, y: e.top};
});
// pointsArray.unshift({x: 35*vw,y: 95*vh });
// pointsArray.unshift({x: 45*vw,y: 90*vh });
// pointsArray.unshift({x: 55*vw,y: 95*vh});
let firesArray = [];
//pointsArray = pointsArray.reverse();
if(params.shuffleFlameShape) pointsArray = shuffleArray(pointsArray);
for(var i=0; i<pointsArray.length / params.outLineGroupSize; i++){
let subArray = pointsArray.slice(i*params.outLineGroupSize, (i+1)*params.outLineGroupSize);
let convexHull = new ConvexHullGrahamScan();
subArray.forEach((e)=>{
if(!e) return;
convexHull.addPoint(e.x, e.y);
});
convexHull.addPoint(fireX, fireY);
convexHull.addPoint(fireX + 15, fireY - 10);
convexHull.addPoint(fireX - 15, fireY - 10);
subArray = convexHull.getHull();
const fire = new fabric.Polyline(subArray.filter(e=>e),
{
fill: 'rgb(255, 180, 0)',
stroke: 'rgba(230, 130, 0, 0)',
selectable: false,
opacity: 1,
centeredScaling: true
});
fire.gradient = {};
fire.gradient.y1 = params.gradientStop0*vh;
fire.gradient.y2 = params.gradientStop1*vh;
let color0 = `rgba(
${params.fireGradient0[0]},
${params.fireGradient0[1]},
${params.fireGradient0[2]},
${params.fireGradient0[3]})`;
let color1 = `rgba(
${params.fireGradient1[0]},
${params.fireGradient1[1]},
${params.fireGradient1[2]},
${params.fireGradient1[3]})`;
const gradientopt = {
y1: fire.gradient.y1,
y2: fire.gradient.y2,
colorStops: {0: color0, 1: color1}
};
fire.setGradient('fill', gradientopt);
canvas.add(fire);
}
Engine.update(engine);
requestAnimationFrame(render);
const r = params.circleSizeMin+Math.random()*params.circleSizeRandom;
addToWorld({
type: 'circ',
fill: params.particleColor,
x: fireX,
y: fireY,
r: r,
action: function(e){
if(e.opacity <= 0.1){
removeFromWorld(e);
}
e.set({
left: e.matter.position.x - e.radius,
top: e.matter.position.y - e.radius,
opacity: e.opacity - (params.particleFadeAway + Math.random()*params.particleFadeAwayRandomness)
});
}
});
canvas.renderAll();
}
render();
$('.upper-canvas').on('click', (e)=>{
fireX = e.offsetX;
fireY = e.offsetY;
});
//# sourceURL=pen.js
</script>
</body></html>