src/profile/elevationComponent.js
function profileElevationComponent(ngeoDebounce) {
  return {
    restrict: 'A',
    /**
     * @param {angular.IScope} scope Scope.
     * @param {JQuery} element Element.
     * @param {angular.IAttributes} attrs Attributes.
     */
    link: (scope, element, attrs) => {

      const optionsAttr = attrs['ngeoProfileOptions'];
      console.assert(optionsAttr !== undefined);

      const selection = d3select(element[0]);
      let profile, elevationData, poiData;

      scope.$watchCollection(optionsAttr, (newVal) => {

        /** @type {ProfileOptions} */
        const options = Object.assign({}, newVal);

        if (options !== undefined) {

          // proxy the hoverCallback and outCallbackin order to be able to
          // call $applyAsync
          //
          // We're using $applyAsync here because the callback may be
          // called inside the Angular context. For example, it's the case
          // when the user hover's the line geometry on the map and the
          // profileHighlight property is changed.
          //
          // For that reason we use $applyAsync instead of $apply here.
          if (options.hoverCallback !== undefined) {
            const origHoverCallback = options.hoverCallback;
            options.hoverCallback = function(...args) {
              origHoverCallback(...args);
              scope.$applyAsync();
            };
          }

          if (options.outCallback !== undefined) {
            const origOutCallback = options.outCallback;
            options.outCallback = function() {
              origOutCallback();
              scope.$applyAsync();
            };
          }

          profile = ngeoProfileD3Elevation(options);
          refreshData();
        }
      });

      scope.$watch(attrs['ngeoProfile'], (newVal, oldVal) => {
        elevationData = newVal;
        refreshData();
      });

      scope.$watch(attrs['ngeoProfilePois'], (newVal, oldVal) => {
        poiData = newVal;
        refreshData();
      });

      scope.$watch(attrs['ngeoProfileHighlight'],
        (newVal, oldVal) => {
          if (newVal === undefined) {
            return;
          }
          if (newVal > 0) {
            profile.highlight(newVal);
          } else {
            profile.clearHighlight();
          }
        });

      olEvents.listen(window, 'resize', ngeoDebounce(refreshData, 50, true));

      /**
       * @param {Event|import("ol/events/Event.js").default=} evt Event
       */
      function refreshData(evt) {
        if (profile !== undefined) {
          selection.datum(elevationData).call(profile);
          if (elevationData !== undefined) {
            profile.showPois(poiData);
          }
        }
      }
    }
  };
}
function profileElevationComponent(ngeoDebounce) {
  return {
    restrict: 'A',
    /**
     * @param {angular.IScope} scope Scope.
     * @param {JQuery} element Element.
     * @param {angular.IAttributes} attrs Attributes.
     */
    link: (scope, element, attrs) => {

      const optionsAttr = attrs['ngeoProfileOptions'];
      console.assert(optionsAttr !== undefined);

      const selection = d3select(element[0]);
      let profile, elevationData, poiData;

      scope.$watchCollection(optionsAttr, (newVal) => {

        /** @type {ProfileOptions} */
        const options = Object.assign({}, newVal);

        if (options !== undefined) {

          // proxy the hoverCallback and outCallbackin order to be able to
          // call $applyAsync
          //
          // We're using $applyAsync here because the callback may be
          // called inside the Angular context. For example, it's the case
          // when the user hover's the line geometry on the map and the
          // profileHighlight property is changed.
          //
          // For that reason we use $applyAsync instead of $apply here.
          if (options.hoverCallback !== undefined) {
            const origHoverCallback = options.hoverCallback;
            options.hoverCallback = function(...args) {
              origHoverCallback(...args);
              scope.$applyAsync();
            };
          }

          if (options.outCallback !== undefined) {
            const origOutCallback = options.outCallback;
            options.outCallback = function() {
              origOutCallback();
              scope.$applyAsync();
            };
          }

          profile = ngeoProfileD3Elevation(options);
          refreshData();
        }
      });

      scope.$watch(attrs['ngeoProfile'], (newVal, oldVal) => {
        elevationData = newVal;
        refreshData();
      });

      scope.$watch(attrs['ngeoProfilePois'], (newVal, oldVal) => {
        poiData = newVal;
        refreshData();
      });

      scope.$watch(attrs['ngeoProfileHighlight'],
        (newVal, oldVal) => {
          if (newVal === undefined) {
            return;
          }
          if (newVal > 0) {
            profile.highlight(newVal);
          } else {
            profile.clearHighlight();
          }
        });

      olEvents.listen(window, 'resize', ngeoDebounce(refreshData, 50, true));

      /**
       * @param {Event|import("ol/events/Event.js").default=} evt Event
       */
      function refreshData(evt) {
        if (profile !== undefined) {
          selection.datum(elevationData).call(profile);
          if (elevationData !== undefined) {
            profile.showPois(poiData);
          }
        }
      }
    }
  };
}
function profileElevationComponent ( ngeoDebounce ) { return { restrict : 'A' , /**
     * @param {angular.IScope} scope Scope.
     * @param {JQuery} element Element.
     * @param {angular.IAttributes} attrs Attributes.
     */ link : ( scope , element , attrs ) => { const optionsAttr = attrs [ 'ngeoProfileOptions' ] ; console . assert ( optionsAttr !== undefined ) ; const selection = d3select ( element [ 0 ] ) ; let profile , elevationData , poiData ; scope . $watchCollection ( optionsAttr , ( newVal ) => { /** @type {ProfileOptions} */ const options = Object . assign ( { } , newVal ) ; if ( options !== undefined ) { // proxy the hoverCallback and outCallbackin order to be able to // call $applyAsync // // We're using $applyAsync here because the callback may be // called inside the Angular context. For example, it's the case // when the user hover's the line geometry on the map and the // profileHighlight property is changed. // // For that reason we use $applyAsync instead of $apply here. if ( options . hoverCallback !== undefined ) { const origHoverCallback = options . hoverCallback ; options . hoverCallback = function ( ... args ) { origHoverCallback ( ... args ) ; scope . $applyAsync ( ) ; } ; } if ( options . outCallback !== undefined ) { const origOutCallback = options . outCallback ; options . outCallback = function ( ) { origOutCallback ( ) ; scope . $applyAsync ( ) ; } ; } profile = ngeoProfileD3Elevation ( options ) ; refreshData ( ) ; } } ) ; scope . $watch ( attrs [ 'ngeoProfile' ] , ( newVal , oldVal ) => { elevationData = newVal ; refreshData ( ) ; } ) ; scope . $watch ( attrs [ 'ngeoProfilePois' ] , ( newVal , oldVal ) => { poiData = newVal ; refreshData ( ) ; } ) ; scope . $watch ( attrs [ 'ngeoProfileHighlight' ] , ( newVal , oldVal ) => { if ( newVal === undefined ) { return ; } if ( newVal > 0 ) { profile . highlight ( newVal ) ; } else { profile . clearHighlight ( ) ; } } ) ; olEvents . listen ( window , 'resize' , ngeoDebounce ( refreshData , 50 , true ) ) ; /**
       * @param {Event|import("ol/events/Event.js").default=} evt Event
       */ function refreshData ( evt ) { if ( profile !== undefined ) { selection . datum ( elevationData ) . call ( profile ) ; if ( elevationData !== undefined ) { profile . showPois ( poiData ) ; } } } } } ; }
Provides a directive used to insert an elevation profile chart
in the DOM.

Example:

<div ngeo-profile="ctrl.profileData"
ngeo-profile-options="ctrl.profileOptions"
ngeo-profile-pois="ctrl.profilePois">
</div>

Where `ctrl.profileOptions` is of type {@link ProfileOptions}; `ctrl.profileData` and `ctrl.profilePois`
are arrays which will be processed by `distanceExtractor` `{function(Object): number}`,
`linesConfiguration` `{Object.<string, LineConfiguration>}` {@link LineConfiguration} and
{@link PoiExtractor}.

See our live example: [../examples/profile.html](../examples/profile.html)

@htmlAttribute {?Object} ngeo-profile The profile data.
@htmlAttribute {ProfileOptions} ngeo-profile-options The options.
@htmlAttribute {?Array} ngeo-profile-pois The data for POIs.
@htmlAttribute {*} ngeo-profile-highlight Any property on the scope which
evaluated value may correspond to distance from origin.
@param {import("ngeo/misc/debounce.js").miscDebounce<function((Event|import('ol/events/Event.js').default)): void>} ngeoDebounce
ngeo Debounce factory.
@return {angular.IDirective} Directive Definition Object.
@ngInject
@ngdoc directive
@ngname ngeoProfile
Provides a directive used to insert an elevation profile chart in the DOM .