| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 | 
							- /**
 -  * @Author: Caven
 -  * @Date: 2021-01-18 17:46:40
 -  */
 - 
 - class WindCanvas {
 -   constructor(ctx) {
 -     this.options = {}
 -     this.particles = []
 -     this.ctx = ctx
 -     this.animationLoop = undefined
 -     this.animate = this.animate.bind(this)
 -   }
 - 
 -   /**
 -    *
 -    * @param m
 -    * @param min
 -    * @param max
 -    * @param colorScale
 -    * @returns {number}
 -    * @private
 -    */
 -   _indexFor(m, min, max, colorScale) {
 -     return Math.max(
 -       0,
 -       Math.min(
 -         colorScale.length - 1,
 -         Math.round(((m - min) / (max - min)) * (colorScale.length - 1))
 -       )
 -     )
 -   }
 - 
 -   /**
 -    *
 -    * @private
 -    */
 -   _moveParticles() {
 -     if (!this.particles || !this.particles.length) {
 -       return
 -     }
 -     let width = this.ctx.canvas.width
 -     let height = this.ctx.canvas.height
 -     let particles = this.particles
 -     let maxAge = this.options.maxAge
 -     let velocityScale =
 -       typeof this.options.velocityScale === 'function'
 -         ? this.options.velocityScale()
 -         : this.options.velocityScale
 -     for (let i = 0; i < particles.length; i++) {
 -       let particle = particles[i]
 -       if (particle.age > maxAge) {
 -         particle.age = 0
 -         this.field.randomize(particle, width, height, this.unProject)
 -       }
 -       let x = particle.x
 -       let y = particle.y
 -       let vector = this.field.interpolatedValueAt(x, y)
 -       if (vector === null) {
 -         particle.age = maxAge
 -       } else {
 -         let xt = x + vector.u * velocityScale
 -         let yt = y + vector.v * velocityScale
 -         if (this.field.hasValueAt(xt, yt)) {
 -           particle.xt = xt
 -           particle.yt = yt
 -           particle.m = vector.m
 -         } else {
 -           particle.x = xt
 -           particle.y = yt
 -           particle.age = maxAge
 -         }
 -       }
 -       particle.age++
 -     }
 -   }
 - 
 -   /**
 -    *
 -    * @private
 -    */
 -   _drawParticles() {
 -     if (!this.particles || !this.particles.length) {
 -       return
 -     }
 -     let particles = this.particles
 -     let prev = this.ctx.globalCompositeOperation
 -     this.ctx.globalCompositeOperation = 'destination-in'
 -     this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height)
 -     this.ctx.globalCompositeOperation = prev
 -     this.ctx.globalAlpha = this.options.globalAlpha
 -     this.ctx.fillStyle = 'rgba(0, 0, 0, ' + this.options.globalAlpha + ')'
 -     this.ctx.lineWidth = this.options.lineWidth ? this.options.lineWidth : 1
 -     this.ctx.strokeStyle = this.options.colorScale
 -       ? this.options.colorScale
 -       : '#fff'
 -     let i = 0
 -     let len = particles.length
 -     if (this.field && len > 0) {
 -       let min = void 0
 -       let max = void 0
 -       if (this.options.minVelocity && this.options.maxVelocity) {
 -         min = this.options.minVelocity
 -         max = this.options.maxVelocity
 -       } else {
 -         let _a = this.field.range
 -         min = _a[0]
 -         max = _a[1]
 -       }
 -       for (; i < len; i++) {
 -         this[
 -           this.options.useCoordsDraw
 -             ? '_drawCoordsParticle'
 -             : '_drawPixelParticle'
 -         ](particles[i], min, max)
 -       }
 -     }
 -   }
 - 
 -   /**
 -    *
 -    * @param particle
 -    * @param min
 -    * @param max
 -    */
 -   _drawPixelParticle(particle, min, max) {
 -     let pointPrev = [particle.x, particle.y]
 -     let pointNext = [particle.xt, particle.yt]
 -     if (
 -       pointNext &&
 -       pointPrev &&
 -       pointNext[0] &&
 -       pointNext[1] &&
 -       pointPrev[0] &&
 -       pointPrev[1] &&
 -       particle.age <= this.options.maxAge
 -     ) {
 -       this._drawStroke(pointPrev, pointNext, particle, min, max)
 -     }
 -   }
 - 
 -   /**
 -    *
 -    * @param particle
 -    * @param min
 -    * @param max
 -    */
 -   _drawCoordsParticle(particle, min, max) {
 -     let source = [particle.x, particle.y]
 -     let target = [particle.xt, particle.yt]
 -     if (
 -       target &&
 -       source &&
 -       target[0] &&
 -       target[1] &&
 -       source[0] &&
 -       source[1] &&
 -       this.intersectsCoordinate(target) &&
 -       particle.age <= this.options.maxAge
 -     ) {
 -       let pointPrev = this.project(source)
 -       let pointNext = this.project(target)
 -       this._drawStroke(pointPrev, pointNext, particle, min, max)
 -     }
 -   }
 - 
 -   /**
 -    *
 -    * @param pointPrev
 -    * @param pointNext
 -    * @param particle
 -    * @param min
 -    * @param max
 -    * @private
 -    */
 -   _drawStroke(pointPrev, pointNext, particle, min, max) {
 -     if (pointPrev && pointNext) {
 -       this.ctx.beginPath()
 -       this.ctx.moveTo(pointPrev[0], pointPrev[1])
 -       this.ctx.lineTo(pointNext[0], pointNext[1])
 -       if (typeof this.options.colorScale === 'function') {
 -         this.ctx.strokeStyle = this.options.colorScale(particle.m)
 -       } else if (Array.isArray(this.options.colorScale)) {
 -         let colorIdx = this._indexFor(
 -           particle.m,
 -           min,
 -           max,
 -           this.options.colorScale
 -         )
 -         this.ctx.strokeStyle = this.options.colorScale[colorIdx]
 -       }
 -       if (typeof this.options.lineWidth === 'function') {
 -         this.ctx.lineWidth = this.options.lineWidth(particle.m)
 -       }
 -       particle.x = particle.xt
 -       particle.y = particle.yt
 -       this.ctx.stroke()
 -     }
 -   }
 - 
 -   /**
 -    *
 -    * @returns {[]|*[]}
 -    * @private
 -    */
 -   _prepareParticlePaths() {
 -     let width = this.ctx.canvas.width
 -     let height = this.ctx.canvas.height
 -     let particleCount =
 -       typeof this.options.paths === 'function'
 -         ? this.options.paths(this)
 -         : this.options.paths
 -     let particles = []
 -     if (!this.field) {
 -       return []
 -     }
 -     for (let i = 0; i < particleCount; i++) {
 -       particles.push(
 -         this.field.randomize(
 -           {
 -             age: Math.floor(Math.random() * this.options.maxAge)
 -           },
 -           width,
 -           height,
 -           this.unProject
 -         )
 -       )
 -     }
 -     return particles
 -   }
 - 
 -   /**
 -    *
 -    */
 -   project() {
 -     throw new Error('project must be overriden')
 -   }
 - 
 -   /**
 -    *
 -    */
 -   unProject() {
 -     throw new Error('unProject must be overriden')
 -   }
 - 
 -   /**
 -    *
 -    * @param coordinates
 -    */
 -   intersectsCoordinate(coordinates) {
 -     throw new Error('must be override')
 -   }
 - 
 -   /**
 -    *
 -    */
 -   prerender() {
 -     if (!this.field) {
 -       return
 -     }
 -     this.particles = this._prepareParticlePaths()
 -     if (!this.starting && !this.forceStop) {
 -       this.starting = true
 -       this._then = Date.now()
 -       this.animate()
 -     }
 -   }
 - 
 -   /**
 -    *
 -    * @returns {WindCanvas}
 -    */
 -   render() {
 -     this._moveParticles()
 -     this._drawParticles()
 -     return this
 -   }
 - 
 -   clearCanvas() {
 -     this.stop()
 -     this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height)
 -     this.forceStop = false
 -   }
 - 
 -   /**
 -    *
 -    */
 -   start() {
 -     this.starting = true
 -     this.forceStop = false
 -     this._then = Date.now()
 -     this.animate()
 -   }
 - 
 -   /**
 -    *
 -    */
 -   stop() {
 -     cancelAnimationFrame(this.animationLoop)
 -     this.starting = false
 -     this.forceStop = true
 -   }
 - 
 -   /**
 -    *
 -    */
 -   animate() {
 -     if (this.animationLoop) {
 -       cancelAnimationFrame(this.animationLoop)
 -     }
 -     this.animationLoop = requestAnimationFrame(this.animate)
 -     let now = Date.now()
 -     let delta = now - this._then
 -     if (delta > this.options.frameRate) {
 -       this._then = now - (delta % this.options.frameRate)
 -       this.render()
 -     }
 -   }
 - 
 -   /**
 -    *
 -    * @param field
 -    * @returns {WindCanvas}
 -    */
 -   setData(field) {
 -     this.field = field
 -     return this
 -   }
 - 
 -   /**
 -    *
 -    * @param options
 -    * @returns {WindCanvas}
 -    */
 -   setOptions(options) {
 -     this.options = options
 -     if (!this.options?.maxAge && this.options?.particleAge) {
 -       this.options.maxAge = Number(this.options.particleAge)
 -     }
 -     if (!this.options?.paths && this.options?.particleMultiplier) {
 -       this.options.paths = Math.round(
 -         this.options.width *
 -           this.options.height *
 -           Number(this.options.particleMultiplier)
 -       )
 -     }
 -     return this
 -   }
 - }
 - 
 - export default WindCanvas
 
 
  |