Fabric.js

Fabric.jsis a powerful and simple JavaScript HTML5 canvas library that provides an interactive object model.

Using Fabric.js, you can create and populate objects on canvas -- objects like simple geometrical shapes or complex shapes consisting of hundreds or thousands of simple paths or good old images.

You can give any shape a gradient.

You can add text and dynamically manipulate its size, alignment, font family, and other properties and apply image filters to images.

There's the built-in animation support.

You can group objects and manipulate them at the same time.

You can add shadow to any object or make it draggable only by its content.

Objects can be easily flipped in any direction. Or locked in movement, scaling, etc.

There is an extensive event system.

You can clip any object to any shape or use a pattern to fill its content.

Canvas can be serialized to JSON or SVG, and restored at any time and, of course, use free drawing to create anything you like.

SVG Animation
RESETRUNFULL
<!DOCTYPE html>
<html>
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/451/fabric.min.js" 
          integrity="sha512-qeu8RcLnpzoRnEotT3r1CxB17JtHrBqlfSTOm4MQzb7efBdkcL03t343gyRmI6OTUW6iI+hShiysszISQ/IahA==" 
          crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
  <canvas id="c" width="400" height="400"></canvas>
  <script>
    (function() {
      var canvas = this.__canvas = new fabric.Canvas('c');
      fabric.Object.prototype.transparentCorners = false;
      fabric.Object.prototype.objectCaching = false;
      var minScale = 1, maxScale = 2;
      fabric.loadSVGFromURL('/shared/angels.svg', function(objects, options) {
        var obj = fabric.util.groupSVGElements(objects, options);
        canvas.add(obj);
        obj.set({
          left: 80,
          top: 90,
          angle: -30,
          direction: 1,
          shadow: {color: 'rgba(0,0,0,0.3)'}
        });
        // animate angle back and forth (every 2 second)
        obj.animate({angle: 30}, {
          duration: 2000,
          easing: fabric.util.ease.easeOutCubic,
          onChange: canvas.renderAndResetBound,
          onComplete: function onComplete() {
            obj.animate({
              angle: Math.round(obj.angle) === 30 ? -30 : 30
            }, {
              duration: 2000,
              onComplete: onComplete
            });
          }
        });
        // animate scale and shadow (every second)
        (function animate(dir) {
          var options = {
            easing: fabric.util.ease.easeOutCubic,
            duration: 1000
          };
          obj.animate({
            scaleX: dir ? maxScale : minScale,
            scaleY: dir ? maxScale : minScale
          }, options);
          obj.animate({
            'shadow.offsetX': dir ? 20 : 0.00001,
            'shadow.offsetY': dir ? 20 : 0.00001
          }, options);
          obj.animate({
            'shadow.blur': dir ? 20 : 0
          }, fabric.util.object.extend({
            onChange: canvas.renderAndResetBound,
            onComplete: function() {
              obj.direction = !obj.direction;
              animate(obj.direction);
            }
          }, options));
        })(1);
      });
    })();
  </script>
</body>
</html>