import ol_interaction_Clip from './Clip.js' import ol_coordinate_cspline from '../render/Cspline.js' /** Blob interaction to clip layers in a blob * @constructor * @extends {ol_interaction_Clip} * @param {*} options blob options * @param {number} options.radius radius of the clip, default 100 * @param {ol.layer|Array} options.layers layers to clip * @param {number} [options.stiffness=20] spring stiffness coef, default 20 * @param {number} [options.damping=7] spring damping coef * @param {number} [options.mass=1] blob mass * @param {number} [options.points=10] number of points for the blob polygon * @param {number} [options.tension=.5] blob polygon spline tension * @param {number} [options.fuss] bob fussing factor * @param {number} [options.amplitude=1] blob deformation amplitude factor */ var ol_interaction_Blob = class olinteractionBlob extends ol_interaction_Clip { constructor(options) { super(options); } /** Animate the blob * @private */ precompose_(e) { if (!this.getActive()) return; var ctx = e.context; var ratio = e.frameState.pixelRatio; ctx.save(); if (!this.pos) { ctx.beginPath(); ctx.moveTo(0, 0); ctx.clip(); return; } var pt = [this.pos[0], this.pos[1]]; var tr = e.inversePixelTransform; if (tr) { pt = [ (pt[0] * tr[0] - pt[1] * tr[1] + tr[4]), (-pt[0] * tr[2] + pt[1] * tr[3] + tr[5]) ]; } else { pt[0] *= ratio; pt[1] *= ratio; } // Time laps if (!this.frame) this.frame = e.frameState.time; var dt = e.frameState.time - this.frame; this.frame = e.frameState.time; // Blob position pt = this._getCenter(pt, dt); // Blob geom var blob = this._calculate(dt); // Draw var p = blob[0]; ctx.beginPath(); ctx.moveTo(pt[0] + p[0], pt[1] + p[1]); for (var i = 1; p = blob[i]; i++) { ctx.lineTo(pt[0] + p[0], pt[1] + p[1]); } ctx.clip(); e.frameState.animate = true; } /** Get blob center with kinetic * @param {number} dt0 time laps * @private */ _getCenter(pt, dt0) { if (!this._center) { this._center = pt; this._velocity = [0, 0]; } else { var k = this.get('stiffness') || 20; // stiffness var d = -1 * (this.get('damping') || 7); // damping var mass = Math.max(this.get('mass') || 1, .1); var dt = Math.min(dt0 / 1000, 1 / 30); var fSpring = [ k * (pt[0] - this._center[0]), k * (pt[1] - this._center[1]) ]; var fDamping = [ d * this._velocity[0], d * this._velocity[1] ]; var accel = [ (fSpring[0] + fDamping[0]) / mass, (fSpring[1] + fDamping[1]) / mass ]; this._velocity[0] += accel[0] * dt; this._velocity[1] += accel[1] * dt; this._center[0] += this._velocity[0] * dt; this._center[1] += this._velocity[1] * dt; } return this._center; } /** Calculate the blob geom * @param {number} dt time laps * @returns {Array} * @private */ _calculate(dt) { var i, nb = this.get('points') || 10; if (!this._waves || this._waves.length !== nb) { this._waves = []; for (i = 0; i < nb; i++) { this._waves.push({ angle: Math.random() * Math.PI, noise: Math.random() }); } } var blob = []; var speed = (this._velocity[0] * this._velocity[0] + this._velocity[1] * this._velocity[1]) / 500; this._rotation = (this._rotation || 0) + (this._velocity[0] > 0 ? 1 : -1) * Math.min(.015, speed / 70000 * dt); for (i = 0; i < nb; i++) { var angle = i * 2 * Math.PI / nb + this._rotation; var radius = this.radius + Math.min(this.radius, speed); var delta = Math.cos(this._waves[i].angle) * radius / 4 * this._waves[i].noise * (this.get('amplitude') || 1); blob.push([ (this.radius + delta) * Math.cos(angle), (this.radius + delta) * Math.sin(angle) ]); // Add noise this._waves[i].angle += (Math.PI + Math.random() + speed / 200) / 350 * dt * (this.get('fuss') || 1); this._waves[i].noise = Math.min(1, Math.max(0, this._waves[i].noise + (Math.random() - .5) * .1 * (this.get('fuss') || 1))); } blob.push(blob[0]); return ol_coordinate_cspline(blob, { tension: this.get('tension') }); } } export default ol_interaction_Blob