<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="initial-scale=1.0, width=device-width, viewport-fit=cover">
    <title>"effect arc welding"</title>
    <meta name="description" content="the effect of arc welding">
</head>
<body>
  
<div id='container'>
    <canvas id="canvas">Canvas is not supported in your browser.</canvas>
   <div id="btncontainer">
    <button id="again">again</button>
    <button id="clear"> clear</button>
    <input id="checkbox" name="cb" type="checkbox">
    <label for="checkbox">use tween</label>
</div>
</div>
 
  
<svg
   xmlns:svg="http://www.w3.org/2000/svg"
   version="1.1"
   id="svg1"
   viewBox="0 0 744 1052"
   width="100%"
   height="100%"
   >
    <path
       id="path13350"
       d="M 100.87821,201.69415 C 82.149052,206.10506 112.88048,218.0941 108.49364,200.45444 104.33539,188.01005 75.41301,188.41034 69.52482,202.66647 62.908356,219.94953 75.285706,241.57505 95.174979,232.99936 99.915328,230.63746 104.13926,226.82928 107.04895,222.44215"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13352"
       d="M 134.71399,177.92312 C 128.85335,179.46166 132.08227,190.07908 138.69176,186.73422 142.90603,183.05571 138.38436,177.29459 134.71399,177.92312 Z"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13354"
       d="M 123.98337,196.97017 C 131.39523,199.69109 164.90854,194.71141 133.81593,199.47106 131.27875,211.22653 145.36874,230.29489 125.50022,230.14306 118.84947,231.84369 131.45516,230.32168 143.31894,230.0189 145.80091,230.63831 144.22049,230.44561 147.25071,230.72275"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13356"
       d="M 180.25177,178.2524 C 180.50412,195.54331 170.96104,223.01528 175.85516,231.20184 179.02866,237.61947 193.85561,238.90221 199.61214,230.54767"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13358"
       d="M 157.10833,190.93679 C 172.148,192.17468 191.1346,197.90275 204.0628,187.82132"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13360"
       d="M 225.72617,195.81893 C 231.40262,195.4829 240.32979,197.09841 245.17361,193.67544"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13362"
       d="M 238.77796,196.27758 C 237.11193,207.11584 237.46213,217.92544 236.77516,228.98994"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13364"
       d="M 222.31051,232.99553 C 232.17221,229.1777 244.01924,228.32453 254.13274,231.66033"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13368"
       d="M 277.94377,199.83811 C 267.13551,192.89914 275.92512,187.95864 288.06766,188.80289 299.57787,189.02314 315.25403,190.04631 297.30453,200.11525 287.81953,204.53043 265.37139,225.32695 274.37067,231.59013 284.68461,234.87492 314.97235,235.01392 310.4979,226.1174 309.00527,222.50934 294.1979,222.81256 297.29488,227.10356"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13370"
       d="M 339.1826,210.62581 C 349.46642,209.97631 370.09187,214.92453 373.60061,205.71577 370.09031,191.00459 345.80666,188.67429 337.23935,198.87821 332.06055,208.67181 337.60909,235.93207 356.67102,234.86234 381.86707,236.19416 374.29317,215.08603 361.66771,220.851 361.66771,220.851 360.77862,223.2913 361.09722,224.41436 361.48451,225.77955 363.77972,228.26877 363.77972,228.26877"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13372"
       d="M 385.87848,192.51924 C 402.99328,189.90374 397.2324,208.83316 399.17073,220.02914 401.73839,230.74501 402.73696,236.90083 390.85456,234.21328"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13374"
       d="M 400.59039,216.13247 C 405.83772,208.42537 414.06269,185.278 422.68916,191.37567 432.33345,205.20611 411.74478,242.23566 436.78292,232.20431"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13376"
       d="M 458.19554,226.54207 C 478.00142,224.21908 451.60426,205.44544 452.40968,223.42526 454.67367,242.00748 494.83697,239.03726 493.41964,219.95781 495.00309,199.51326 469.73058,199.04785 456.00799,202.28422 454.96765,190.48292 452.09672,176.22976 469.97606,179.71795 478.77687,182.81302 488.96324,183.12752 495.13603,177.13974"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13382"
       d="M 556.23989,177.2201 C 548.75932,190.24587 530.72099,181.23432 518.5329,179.93995 517.61462,188.00766 519.04429,196.88179 518.9347,203.22864 534.32308,201.70582 564.79586,201.56554 559.31501,220.07959 551.96095,238.3115 523.18123,246.91387 516.75088,224.04196 509.96553,210.57209 539.28128,213.7483 526.29065,223.7975"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       id="path13352-6"
       d="M 229.89256,179.86893 C 225.09132,179.02383 227.26994,192.00441 233.87033,188.68003 236.49688,184.45494 232.61369,179.9245 229.89256,179.86893 Z"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</svg>
</body>
</html>
body {
  background: #000;
  margin: 0;
}

#container{
  position: relative;
  width: 100%;
  height: 100%;
}

canvas {
  cursor: crosshair;
  display: block;
}
#canvas{
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1;
}
button{
  margin: 10px;
  padding: 5px;
  background-color: green;
  color: white;
  cursor: pointer;
}
label{
  color: white;
}

#btncontainer{
  position: absolute;
  z-index: 2;
}

setTimeout(() => {
  run();
}, 2000);

function run(){

    var useTween = false;
    var easeTween = '';
    let aw; // instance of ArcWelding

    let cb = document.getElementById("checkbox");

    cb.addEventListener("change", () => {
        useTween = true;
        easeTween = "Power1.easeInOut";
    });

    if(useTween){
        aw = new ArcWeldingTw();
    }else{
        aw = new ArcWelding();
    }
    aw.run();

    let btnClear = document.getElementById("clear");
    let btnAgain = document.getElementById("again");
    btnClear.addEventListener("click", () => {
        aw.clearScreen();
    });
    btnAgain.addEventListener("click", () => {
        aw.againDraw();
    });
    
}

class ArcWelding{
    constructor(){
        this.canvas = document.getElementById('canvas'),
        this.ctx = canvas.getContext('2d');
        // full screen dimensions
        this.cw = window.innerWidth;
        this.ch = window.innerHeight;
        // particle collection
        this.particles = [];
        this.weldSeam = [];

        this.mousedown = false;
        // mouse x coordinate,
        this.mx;
        // mouse y coordinate
        this.my;
        
        this.nextStep;
        // set canvas dimensions
        this.canvas.width = this.cw;
        this.canvas.height = this.ch;
        console.log(this.canvas.width, this.canvas.height);
        this.init();
    }
    
    init(){
        // mouse event bindings
        // update the mouse coordinates on mousemove
        this.canvas.addEventListener( 'mousemove', (event) => {
            // this.mx = event.pageX - canvas.offsetLeft;
            // this.my = event.pageY - canvas.offsetTop;
            this.mx = event.clientX;
            this.my = event.clientY;
        });

        // toggle mousedown state and prevent canvas from being selected
        this.canvas.addEventListener( 'mousedown', (event) => {
            event.preventDefault();
            this.mousedown = true;
        });

        this.canvas.addEventListener( 'mouseup', (event) => {
            event.preventDefault();
            this.mousedown = false;
        });
    }

    run(){
        let textSvg = document.getElementById('svg1').outerHTML;
        this.paths = Util.extractPathsfromSvg(textSvg);
        this.loop();
        this.writeWord();
    }

    againDraw(){
        console.log("again");
        this.clearScreen();
        let textSvg = document.getElementById('svg1').outerHTML;
        this.paths = Util.extractPathsfromSvg(textSvg);
        this.writeWord();
    }

    clearScreen(){
        console.log("clear");
        this.weldSeam = [];
        this.particles = [];
    }
    
    stop(){
        this.playAnimation = false;
        this.clearScreen();
    }

    // create particle group
    createParticles(x, y, ctx) {
        // increase the particle count for a bigger fire, 
        //beware of the canvas performance hit with the increased particles though
        let _x = x || this.mx;
        let _y = y || this.my;
        let _ctx = ctx || this.ctx;
        let particleCount = 15;
        while(particleCount--) {
            this.particles.push(new Particle(_x, _y, _ctx));
        }
    }


    loop(){
        window.requestAnimationFrame(this.loop.bind(this));
        // setting the composite operation to destination-out will allow us to clear the canvas at a specific opacity, rather than wiping it entirely
       this.ctx.globalCompositeOperation = 'destination-out';
        // decrease the alpha property to create more prominent trails
       this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
       this.ctx.fillRect( 0, 0, this.cw, this.ch );
        // change the composite operation back to our main mode
        // lighter creates bright highlight points as the fireworks and particles overlap each other
       this.ctx.globalCompositeOperation = 'lighter';
        
        if(this.mousedown === true){
            let st = new Stitch(this.mx, this.my, this.ctx);
            this.weldSeam.push(st);
            //console.dir(st);
           this.createParticles();
        }

        // loop over each particle, draw it, update it
        let len = this.particles.length;
        let i = 0;
        for(i = 0; i < len; i++){
            if(this.particles[i] === undefined){

                debugger;
            }
            this.particles[i].draw();
            if(!this.particles[i].update(i)){
                this.particles.splice(i, 1);
                len--;
            }
        }

        this.ctx.globalCompositeOperation = 'destination-over';
        len = this.weldSeam.length;
        for(i = 0; i < len; i++){
            this.weldSeam[i].update();
            this.weldSeam[i].draw();
        }
        this.ctx.globalCompositeOperation = 'lighter';
    }

    writeWord(){
        this.preparePath();
        this.wwLoop();
    }

    wwLoop(){
        if(this.processingPathStep()){
            window.requestAnimationFrame(this.wwLoop.bind(this));
        }
    }

    preparePath(){
        let path = document.createElementNS("http://www.w3.org/2000/svg", "path");
        if(this.paths.length){
            path.setAttribute('d', this.paths.shift())
        }else{
            return false;
        }
        this.path = path;
        this.nextStep = Util.iterator();
        return true;
    }

    processingPathStep(){
        let step = this.nextStep();
        if(step > this.path.getTotalLength()){
            //console.log(this.path.getTotalLength());
            //path.viewBox
            if(!this.preparePath()) return false;
            
        }
        let point = this.path.getPointAtLength(step);
        let st = new Stitch(point.x, point.y, this.ctx, 5);
            this.weldSeam.push(st);
            //console.dir(st);
        this.createParticles(point.x, point.y, this.ctx);
        return true;
    }
}

class ArcWeldingTw extends ArcWelding{
    constructor(){
        super();
        this.totalLenghtAllPath = 0;
        this.curPath = 0;
        this.offset = 0; // length of already traversed paths 
        this.helper = {progress: 0}
        this.helper.update = () => {
            console.log('helper.update');
            this.processingPathStep();
        }    
    }


    run(){
        let svg = document.getElementById('c');
        this.paths = [];
        for(let i = 0; i < svg.children.length; i ++){
            this.paths.push(svg.children[i]);
            this.totalLenghtAllPath += this.paths[i].getTotalLength();
        }
        console.log(this.totalLenghtAllPath);

        this.tw = TweenLite.to(this.helper, 25, {progress: this.totalLenghtAllPath, ease: Power2.easeOut, });
        this.tw.eventCallback("onUpdate", this.helper.update.bind(this));

        this.loop();
        this.writeWord();
    }

    writeWord(){
        this.nextStep = Util.iterator();
        this.curPath = this.paths[this.nextStep()];
       // this.getPath();
    }

    // getPath(){
        
    //     if(!this.curPath){
    //         return false;
    //     }
    //     return true;
    // }

    getPoint(){
        let localProgress = this.helper.progress - this.offset;
        if(localProgress > this.curPath.getTotalLength()){
            
            this.offset += this.curPath.getTotalLength();
            this.curPath = this.paths[this.nextStep()];
            if(!this.curPath){
                return false;
            }
            return this.getPoint();
        }
        return this.curPath.getPointAtLength(localProgress);
    }

    processingPathStep(){

        let point = this.getPoint();
        let st = new Stitch(point.x, point.y, this.ctx, 5);
            this.weldSeam.push(st);
            //console.dir(st);
        this.createParticles(point.x, point.y, this.ctx);
        return true;
    }
}

class Particle{
    constructor(x, y, ctx){
        this.x = x;
        this.y = y;
        this.ctx = ctx;

        let hue = 33;
 
        this.coordinates = [];
        this.coordinateCount = 5;
        while( this.coordinateCount-- ) {
            this.coordinates.push( [ this.x, this.y ] );
        }
        // random angle in all direction
        this.angle = Util.random( 0, Math.PI * 2 );
        this.speed = Util.random( 1, 10 );
        //will slow the particle down
        this.friction = 0.93;
        this.gravity = 3;
        // hue in the range of red-yellow
        this.hue = Util.random(hue - 15, hue + 15);
        this.brightness = Util.random(50, 80);
        this.alpha = 1;
        this.lineW = Util.random(1, 3);
        // speed fade outs
        this.decay = Util.random(0.01, 0.06);
    }

    update(index){
        this.coordinates.pop();
        
        this.coordinates.unshift([this.x, this.y]);
        
        this.speed *= this.friction;
        
        this.x += Math.cos( this.angle ) * this.speed;
        this.y += Math.sin( this.angle ) * this.speed + this.gravity;
        // fade out the particle
        this.alpha -= this.decay;
        
        if( this.alpha <= this.decay ) {
            return false;
        }
        return true;
    }

    draw(){
        this.ctx.beginPath();

        let len = this.coordinates.length - 1;
        this.ctx.moveTo( 
            this.coordinates[ len ][ 0 ], 
            this.coordinates[ len ][ 1 ] 
        );
        this.ctx.lineTo( this.x, this.y );
        this.ctx.strokeStyle = 'hsla(' + this.hue + ', 100%, ' + this.brightness + '%, ' + this.alpha + ')';
        this.ctx.lineWidth = this.lineW;
        this.ctx.stroke();
    }
}

class Stitch {
    constructor(x, y, ctx, radius){
        this.x = x;
        this.y = y;
        this.ctx = ctx;
        this.radius = radius || 10;
        // temperature in degrees Celsius
        this.dC = 0.4;
        this.hue = 33;
        this.brightness = 100;
        this.saturation = 100;
        this.draw();

    }

    update(){
        if(this.hue > 0){
            this.hue -= this.dC;
        }
        if(this.brightness > 60){
            this.brightness -= this.dC;
        }
        if(this.saturation > 0){
            this.saturation -= this.dC;
        }
    }

    draw(){
        let grt = this.ctx.createRadialGradient( this.x, this.y, 0, this.x, this.y, this.radius);

        grt.addColorStop(0.0, 'hsla(' + this.hue + ',' + this.saturation + '%, ' + this.brightness + '%, ' + 1 + ')');
        grt.addColorStop(1.0, 'hsla(' + this.hue + ',' + this.saturation + '%, ' + (this.brightness - 30) + '%, ' + 1 + ')');

        this.ctx.beginPath();
        this.ctx.fill();
        this.ctx.fillStyle = grt;
        this.ctx.beginPath();
        this.ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
        this.ctx.fill();
    }
}

let Util = {
    // get a random number within a range
    random: function( min, max ) {
        return Math.random() * ( max - min ) + min;
    },

    iterator: function(){
        let step = 0;
        return function(){
            return step++;
        }
    },

    extractPathsfromSvg: function(svg){
        let results = svg.match(/<path\b([\s\S]*?)><\/path>/g);
        let paths = [];
        let len = results.length;
        for(let i = 0; i < len; i++){
            let str = results[i];
            let data = str.match(/[^\w]d="([\s\S]*?)"/);
            paths.push(data[1]);
        }
        return paths;
    }
}

Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.2/TweenLite.min.js