芝麻web文件管理V1.00
编辑当前文件:/home/qrafawbu/qrafiqxcreativestudios.com/mkoroundtress.com/js/circleaudioplayer.js
/** * CircleAudioPlayer * * A minimalist audio player represented by a single button in a circle which * fills clockwise as the audio file progresses. * * Isolated to have no requirements. * * @param {object} options * @prop {string} audio * @prop {string} borderColor * @prop {string} playedColor * @prop {string} backgroundColor * @prop {string} iconColor * @prop {number} borderWidth * @prop {number} size * @prop {string} className - class to add to the canvas element * * @method {void} addEventListener (planned, not implemented) * forwards to the canvas' addEventListener or the audio element's * addEventListener, depending on whether or not the event string matches a * media event * * @method {void} setAudio * @param {string} audioUrl * @method {void} setSize * @param {number} size * @method {void} appendTo * @param {DOMElement} element * @method {void} play * @method {void} pause * @method {void} draw - force a redraw */ // requirements // settings var DEFAULTS = { borderColor: "#e3207b", playedColor: "#fff", backgroundColor: "rgba(255,255,255,0)", iconColor: "#e3207b", borderWidth: 2, size: 18, className: 'circle-audio-player' }; // reused values var pi = Math.PI; var doublePi = pi * 2; var arcOffset = -pi / 2; var animTime = 200; var loaderTime = 1800; var CircleAudioPlayer = function (options) { options = options || {}; for (var property in DEFAULTS) { this[property] = options[property] || DEFAULTS[property]; } // create some things we need this._canvas = document.createElement('canvas'); this._canvas.setAttribute('class', this.className + ' is-loading'); this._canvas.addEventListener('mousedown', (function () { if (this.playing) { this.pause(); } else { this.play(); } }).bind(this)); this._ctx = this._canvas.getContext('2d'); // set up initial stuff this.setAudio(options.audio); this.setSize(this.size); // redraw loop (function cAPAnimationLoop (now) { // check if we need to update anything if (this.animating) { this._updateAnimations(now); } if (this._forceDraw || this.playing || this.animating || this.loading) { this._draw(); this._forceDraw = false; } requestAnimationFrame(cAPAnimationLoop.bind(this)); }).call(this, new Date().getTime()); }; CircleAudioPlayer.prototype = { // private methods _animateIcon: function (to, from) { // define a few things the first time this._animationProps = { animStart: null, from: from, to: to }; if (from) { this.animating = true; } else { this._animationProps.current = this._icons[to].slice(); this.draw(); } }, _updateAnimations: function (now) { this._animationProps.animStart = this._animationProps.animStart || now; var deltaTime = now - this._animationProps.animStart; var perc = (1 - Math.cos(deltaTime / animTime * pi / 2)); if (deltaTime >= animTime) { this.animating = false; perc = 1; this._animationProps.current = this._icons[this._animationProps.to].slice(); this.draw(); } else { var from = this._icons[this._animationProps.from]; var current = []; for (var i = 0; i < from.length; i++) { current.push([]); for (var j = 0; j < from[i].length; j++) { current[i].push([]); var to = this._icons[this._animationProps.to][i][j]; current[i][j][0] = from[i][j][0] + (to[0] - from[i][j][0]) * perc; current[i][j][1] = from[i][j][1] + (to[1] - from[i][j][1]) * perc; } } this._animationProps.current = current; } }, _draw: function (progress) { // common settings if (isNaN(progress)) { progress = this.audio.currentTime / this.audio.duration || 0; } // clear existing this._ctx.clearRect(0, 0, this.size, this.size); // draw bg this._ctx.beginPath(); this._ctx.arc(this._halfSize, this._halfSize, this._halfSize - (this.borderWidth / 2), 0, doublePi); this._ctx.closePath(); this._ctx.fillStyle = this.backgroundColor; this._ctx.fill(); // draw border // our active path is already the full circle, so just stroke it this._ctx.lineWidth = this.borderWidth; this._ctx.strokeStyle = this.borderColor; this._ctx.stroke(); // play progress if (progress > 0) { this._ctx.beginPath(); this._ctx.arc(this._halfSize, this._halfSize, this._halfSize - (this.borderWidth / 2), arcOffset, arcOffset + doublePi * progress); this._ctx.strokeStyle = this.playedColor; this._ctx.stroke(); } // icons this._ctx.fillStyle = this.iconColor; if (this.loading) { var loaderOffset = -Math.cos((new Date().getTime() % (loaderTime)) / (loaderTime) * pi) * doublePi - (pi / 3) - (pi / 2); this._ctx.beginPath(); this._ctx.arc(this._halfSize, this._halfSize, this._halfSize / 3, loaderOffset, loaderOffset + pi / 3 * 2); this._ctx.strokeStyle = this.iconColor; this._ctx.stroke(); } else { this._ctx.beginPath(); var icon = (this._animationProps && this._animationProps.current) || this._icons.play; for (var i = 0; i < icon.length; i++) { this._ctx.moveTo(icon[i][0][0], icon[i][0][1]); for (var j = 1; j < icon[i].length; j++) { this._ctx.lineTo(icon[i][j][0], icon[i][j][1]); } } // this._ctx.closePath(); this._ctx.fill(); // stroke to fill in for retina this._ctx.strokeStyle = this.iconColor; this._ctx.lineWidth = 2; this._ctx.lineJoin = 'miter'; this._ctx.stroke(); } }, _setState: function (state) { this.playing = false; this.loading = false; if (state === 'playing') { this.playing = true; this._animateIcon('pause', 'play'); } else if (state === 'loading') { this.loading = true; } else if (this.state !== 'loading') { this._animateIcon('play', 'pause'); } else { this._animateIcon('play', null); } this.state = state; this._canvas.setAttribute('class', this.className + ' is-' + state); this.draw(); }, // public methods draw: function () { this._forceDraw = true; }, setSize: function (size) { this.size = size; this._halfSize = size / 2; // we do this a lot. it's not heavy, but why repeat? this._canvas.width = size; this._canvas.height = size; // set icon paths var iconSize = this.size / 2; var pauseGap = iconSize / 10; var playLeft = Math.cos(pi / 3 * 2) * (iconSize / 2) + this._halfSize; var playRight = iconSize / 2 + this._halfSize; var playHalf = (playRight - playLeft) / 2 + playLeft; var top = this._halfSize - Math.sin(pi / 3 * 2) * (iconSize / 2); var bottom = this.size - top; var pauseLeft = this._halfSize - iconSize / 3; var pauseRight = this.size - pauseLeft; this._icons = { play: [ [ [playLeft, top], [playHalf, (this._halfSize - top) / 2 + top], [playHalf, (this._halfSize - top) / 2 + this._halfSize], [playLeft, bottom] ], [ [playHalf, (this._halfSize - top) / 2 + top], [playRight, this._halfSize], [playRight, this._halfSize], [playHalf, (this._halfSize - top) / 2 + this._halfSize] ] ], pause: [ [ [pauseLeft, top + pauseGap], [this._halfSize - pauseGap, top + pauseGap], [this._halfSize - pauseGap, bottom - pauseGap], [pauseLeft, bottom - pauseGap] ], [ [this._halfSize + pauseGap, top + pauseGap], [pauseRight, top + pauseGap], [pauseRight, bottom - pauseGap], [this._halfSize + pauseGap, bottom - pauseGap] ] ] }; if (this._animationProps && this._animationProps.current) { this._animateIcon(this._animationProps.to); } if (!this.playing) { this.draw(); } }, setAudio: function (audioUrl) { this.audio = new Audio(audioUrl); this._setState('loading'); this.audio.addEventListener('canplaythrough', (function () { this._setState('paused'); }).bind(this)); this.audio.addEventListener('play', (function () { this._setState('playing'); }).bind(this)); this.audio.addEventListener('pause', (function () { // reset when finished if (this.audio.currentTime === this.audio.duration) { this.audio.currentTime = 0; } this._setState('paused'); }).bind(this)); }, appendTo: function (element) { element.appendChild(this._canvas); }, play: function () { this.audio.play(); }, pause: function () { this.audio.pause(); } }; // now init one as an example var cap = new CircleAudioPlayer({ audio: 'http://www.largesound.com/ashborytour/sound/AshboryBYU.mp3', size: 120, borderWidth: 4 }); cap.appendTo(playerContainer);