Source: interaction/multiclips-interaction.js

import Clip from 'ol-ext/interaction/Clip'

/** Clip interaction to clip layers in a circle
 * @constructor
 * @extends {ol.interaction.Pointer}
 * @param {ol.interaction.clip.options} flashlight options param
 *  - radius {number} radius of the clip, default 100
 *  - layers {ol.layer|Array<ol.layer>} layers to clip
 */
class MultiClips extends Clip {
  constructor (options) {
    super(options)
    this.clips_ = []
  // Clip.call(this, options)
  }
}

/* @private
*/
MultiClips.prototype.precompose_ = function (e) {
  const ctx = e.context
  const ratio = e.frameState.pixelRatio
  const resolution = e.frameState.viewState.resolution

  ctx.save()
  ctx.beginPath()

  // Dessin du clip à l'emplacement du curseur (reprise code ol-ext avec un closepath pour fermer le cercle)
  if (this.followPointer) {
    let pt = [this.pos[0], this.pos[1]]
    let radius = this.radius
    const tr = e.inversePixelTransform
    if (tr) {
    // Transform pt
      pt = [
        (pt[0] * tr[0] - pt[1] * tr[1] + tr[4]),
        (-pt[0] * tr[2] + pt[1] * tr[3] + tr[5]),
      ]
      // Get radius / transform
      radius = pt[0] - ((this.pos[0] - radius) * tr[0] - this.pos[1] * tr[1] + tr[4])
    } else {
      pt[0] *= ratio
      pt[1] *= ratio
      radius *= ratio
    }
    ctx.arc(pt[0], pt[1], radius, 0, 2 * Math.PI)
    ctx.closePath()
  }

  // Dessin des clips fixe
  this.clips_.forEach(clip => {
    const pt = this.getMap().getPixelFromCoordinate([clip[0], clip[1]])
    const radius = clip[2] / resolution
    ctx.arc(pt[0], pt[1], radius, 0, 2 * Math.PI)
    ctx.closePath()
  })

  // clip du layer
  ctx.clip()
}

/**
 * Clear all persisted clip on map
 */
MultiClips.prototype.clear = function () {
  this.clips_ = []
  if (this.getMap()) {
    try { this.getMap().renderSync() } catch (e) { /* ok */ }
  }
}

/**
 * Add clip on map
 *
 * @param {ol.Coordinate} coordinate Coordinates of clip center
 * @param {Number | undefined} radius Radius to apply on clip. Default is currentRadius
 */
MultiClips.prototype.addClip = function (coordinate, radius) {
  this.clips_.push([...coordinate, radius || this.radius])
  if (this.getMap()) {
    try { this.getMap().renderSync() } catch (e) { /* ok */ }
  }
}

/**
 * Remove the last clip added to the map
 */
MultiClips.prototype.removeLast = function () {
  this.clips_.pop()
  if (this.getMap()) {
    try { this.getMap().renderSync() } catch (e) { /* ok */ }
  }
}

/**
 * Activate or deactivate the interaction.
 * @param {boolean} active Active.
 * @observable
 * @api
 */
// MultiClips.prototype.setActive = function (isActive) {
//   Pointer.prototype.setActive.call(this, isActive)
//   if (isActive) {
//     for (let i = 0; i < this.layers_.length; i++) {
//       this.layers_[i].un(['precompose', 'prerender'], this.precomposeBind_)
//       this.layers_[i].un(['postcompose', 'postrender'], this.postcomposeBind_)
//     }
//   } else {
//     for (let i = 0; i < this.layers_.length; i++) {
//       this.layers_[i].on(['precompose', 'prerender'], this.precomposeBind_)
//       this.layers_[i].on(['postcompose', 'postrender'], this.postcomposeBind_)
//     }
//   }
//   if (this.getMap()) {
//     try { this.getMap().renderSync() } catch (e) { /* ok */ }
//   }
// }

MultiClips.prototype.setFollowPointer = function (isFollow) {
  this.followPointer = !!isFollow
  if (this.getMap()) {
    try { this.getMap().renderSync() } catch (e) { /* ok */ }
  }
}

export default MultiClips