<svg width="100%" 
     height="100%"
     version="1.1"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"
     id="map-container">

   <text x="50%"
         y="50%"
         fill="silver"
         font-size="55"
         style="opacity: .5;"
         text-anchor="middle">Click area</text>
  
    <svg id="routes-container"></svg>

    <svg id="planes-container">

        <g class="plane">
            <rect x="-24" y="-4"
                  width="48" height="8"></rect>

            <image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAACHFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb++m0AAAAAXRSTlMAQObYZgAAAllJREFUeAHt2olS01AYxfHzmIJaioq4IFCx4lIXXERZEKwWpdWCCqXB0uW8oDPO1Cb03tpMwnfGmfxe4X+SXC5FJpPJZDKpKrDV161AoMeBBdjbYAjsTTKkCns/GTIPcw8pLkBxgR2GLcJanuICAcPqsPacEfdgjeICu4z4BmO3GLUEY21xgTek9hmguECN2gIFnvFDcAyKeARTaxQXoLjAd2oL3KW4AMUFNqktcIHiAscccghDyxy2AkMUF9jmsAbsTFFc4ERc4BnFBSgu8IXaAjcYv8DNNA+Nbbq8HTMaEnvN+AWO2PcVidEpwAhl/vUESdUZu8DjNKc6z9gF8qm+LHrxC3Q5sIqE1hm7wD7TLMDYBd4zpJ3eQTzqBD5Fhm3Bb3avefwPjRY9fj2471R8yYgr8KrQArzWaOEjvGhiDj6LFBdYpYU9eL2ihS14XaWFAH498QZQoIUX8CvSwAFGWdo+2B+tfkSP3mnHrcsIJPWJbs0xbzKXBZ/jTvRNkNRTui3A51K6DdCiU23Mq4zbSGqabmP+U6+M89rhHfgdptoAsRsAHMif0+UAOd6fptxEcq14DaJf2zaSm47fALU0R4AKXTBStVb9o15ECugyBzslOnyGoYAOUF9UXldf1e7CkroBSuoGaKob5PwNdDuchSl/A9kOOwC078MpmJrhWTuwVVY3gLoBVtQNEKgbzKgb4IO6AfwNRDu8CPEON2DtGiNa6t/UchLm1A1QUjdAQ/wcIKduEN3hKQQYNgHxDt9BvMMAEO8QEO9wHQr5y325CWQymUzm//AbFsetgyAKUVUAAAAASUVORK5CYII="
                   x="-12px" y="-12px"
                   height="24px" width="24px"></image>
        </g>

    </svg>
    
</svg>
html,
body {
    width: 100%;
    height: 100%;
    background: #E7DBDB;
    margin: 0;
}

#map-container {
    cursor: cell;
}

#plane-container {
    width: 100%;
    height: 100%;
}

.plane rect {
    fill: #E7DBDB;
    fill-opacity: 1;
}

.plane image {

}

.fly-animation {
    fill: none;
    stroke: rgb(68, 62, 58);
    stroke-width: 2px;
}
/* Example */
window.onclick = function (e) {
  var plane = document.getElementsByClassName('plane')[0];

  var planesContainer = document.getElementById('planes-container');
  var routesContainer = document.getElementById('routes-container');
  var mapContainer = document.getElementById('map-container');
  
  var mapContainerRect = mapContainer.getBoundingClientRect();

  var fly = new Fly(plane, {
    x: mapContainerRect.width / 2,
    y: mapContainerRect.height / 2
  }, {
    x: e.layerX,
    y: e.layerY
  }, 1);

  fly.animate();
};

/**
 * Represents a fly
 * @constructor
 * @param element {HTMLElement}
 * @param fromXY {Object}
 * @param toXY {Object}
 * @param duration {String}
 * */
function Fly(element, fromXY, toXY, duration) {
  this.element = element;
  this.element.setAttribute('visibility', 'hidden');

  var elementRect = element.getBBox();

  this.from = fromXY;
  this.to = toXY;
  this.time = duration;
  this.elementW = elementRect.width;
  this.elementH = elementRect.height;
  
  this.elementX = elementRect.x;
  this.elementY = elementRect.y;
  
  /* Break line width */
  this.dashLength = this.elementW * 4;

  this.container = document.getElementById('routes-container');
  this.path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
  this.path.setAttribute('class', 'fly-animation');
  this.path.style.strokeDasharray = [0, 1].join(' ');
  this.setCenterPoint();
  this.setPath();
  this.containerClear();
  this.container.appendChild(this.path);
}

Fly.prototype.containerClear = function () {
  while (this.container.firstChild) {
    this.container.removeChild(this.container.firstChild);
  }
};

Fly.prototype.setPath = function () {
  var d = [
    'M', this.from.x, ',', this.from.y,
    'C', this.cp1.x, ',', this.cp1.y, this.cp2.x, ',', this.cp2.y, this.to.x, ',', this.to.y
  ].join(' ');
  this.path.setAttribute('d', d);
};

Fly.prototype.setCenterPoint = function () {
  var _x = 0, _y = 0;

  this.cp1 = {};
  this.cp2 = {};

  if (this.to.x > this.from.x && this.from.y > this.to.y) {
    /* start 1 part */
    this.cp1.x = this.from.x;
    this.cp1.y = this.from.y - ((this.from.y - this.to.y) * 0.7);

    this.cp2.x = this.from.x + ((this.to.x - this.from.x) * 0.7);
    this.cp2.y = this.to.y;

    _x = this.to.x - this.from.x;
    _y = this.from.y - this.to.y;

    if (_x <= 120)
      this.cp1.x = this.from.x * 0.77;

    if (_y <= 120)
      this.cp2.y = this.to.y * 0.77;

    if (_x <= 70 && _y <= 70) {
      this.cp1.x = this.from.x;
      this.cp2.y = this.to.y;
    }
    /* end 1 part */
  } else if (this.to.x > this.from.x && this.to.y > this.from.y) {
    /* start 2 part */
    this.cp1.x = this.from.x + ((this.to.x - this.from.x) * 0.7);
    this.cp1.y = this.from.y;

    this.cp2.x = this.to.x;
    this.cp2.y = this.to.y - ((this.to.y - this.from.y) * 0.7);

    _x = this.to.x - this.from.x;
    _y = this.to.y - this.from.y;

    if (_x <= 120)
      this.cp2.x = this.to.x * 1.2;

    if (_y <= 120)
      this.cp1.y = this.from.y * 0.77;

    if (_x <= 70 && _y <= 70) {
      this.cp1.y = this.from.y;
      this.cp2.x = this.to.x;
    }
    /* end 2 part */
  } else if (this.from.x > this.to.x && this.from.y > this.to.y) {
    /* start 2 part */
    this.cp1.x = this.from.x;
    this.cp1.y = this.from.y - ((this.from.y - this.to.y) * 0.7);

    this.cp2.x = this.to.x + ((this.from.x - this.to.x) * 0.7);
    this.cp2.y = this.to.y;

    _x = this.from.x - this.to.x;
    _y = this.to.y - this.from.y;

    if (_x <= 120)
      this.cp1.x = this.from.x * 1.2;

    if (_y <= 120)
      this.cp2.y = this.to.y * 0.77;

    if (_x <= 70 && _y <= 70) {
      this.cp1.y = this.from.y;
      this.cp2.y = this.to.y;
    }

    /* end 3 part */
  } else if (this.to.x < this.from.x && this.to.y > this.from.y) {
    /* start 4 part */
    this.cp1.x = this.from.x + ((this.to.x - this.from.x) * 0.7);
    this.cp1.y = this.from.y;

    this.cp2.x = this.to.x;
    this.cp2.y = this.to.y - ((this.to.y - this.from.y) * 0.7);

    _x = this.from.x - this.to.x;
    _y = this.to.y - this.from.y;

    if (_x <= 120)
      this.cp1.x = this.from.x * 1.2;

    if (_y <= 120)
      this.cp2.y = this.to.y * 0.77;

    if (_x <= 70 && _y <= 70) {
      this.cp1.y = this.from.y;
      this.cp2.y = this.to.y;
    }

    /* end 4 part */
  } else {
    this.cp1.x = this.from.x;
    this.cp1.y = this.from.y;
  }

};

Fly.prototype.animate = function () {
  var self = this;

  this.lineData = {};
  this.lineData.counter = 0;
  this.lineData.length = this.path.getTotalLength();

  this.lineDashData = {};
  this.lineDashData.counter = 0;
  this.lineDashData.counter0 = 0;
  this.lineDashData.length = (this.lineData.length / 2) + (this.dashLength / 2);

  TweenMax.to(this.lineData, this.time, {
    counter: this.lineData.length,
    onUpdate: drawLine,
    ease: Quart.easeIn,
    onComplete: function () {

      TweenMax.to(self.lineDashData, self.time / 1.5, {
        counter: self.lineDashData.length,
        onUpdate: drawDash,
        ease: ElasticOut.ease,
        onStart: function () {
          self.element.setAttribute('visibility', 'visible')
        }
      });

    }
  });

  function drawLine() {
    self.path.style.strokeDasharray = [self.lineData.counter, self.lineData.length].join(' ');
  }

  function drawDash() {

    if (isNaN(self.dashLength)) {
      return;
    }

    self.path.style.strokeDasharray = [self.lineData.counter, self.dashLength].join(' ');
    self.path.style.strokeDashoffset = -1 * self.lineDashData.counter + 'px';

    var p0 = self.path.getPointAtLength(self.lineDashData.counter0 - (self.dashLength / 2)),
      p1 = self.path.getPointAtLength(self.lineDashData.counter - (self.dashLength / 2)),
      angle = Math.atan2(p1.y - p0.y, p1.x - p0.x) * 180 / Math.PI;

    self.lineDashData.counter0 = self.lineDashData.counter;

    self.element.style.transform =
      'translate(' + (p1.x - (self.elementH) - self.elementY) + 'px, ' + (p1.y - (self.elementW / 2 + self.elementX)) + 'px) ' +
      'rotate(' + (angle + 180) + 'deg' + ')';
  }

};

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.4/TweenMax.min.js