multiple-audio-player-plugin
Version:
multiple circular html5 audio player, using svg
229 lines (186 loc) • 9.16 kB
JavaScript
/**
* author : İlker YILMAZ
* url : https://github.com/kuantal/Multiple-circular-player
* inspired by https://github.com/frumbert/circular-player
*/
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(factory);
} else if (typeof exports === 'object') {
module.exports = factory;
} else {
root.lunar = factory();
}
})(this, function () {
'use strict';
var lunar = {};
lunar.hasClass = function (elem, name) {
return new RegExp('(\\s|^)' + name + '(\\s|$)').test(elem.attr('class'));
};
lunar.addClass = function (elem, name) {
!lunar.hasClass(elem, name) && elem.attr('class', (!!elem.getAttribute('class') ? elem.getAttribute('class') + ' ' : '') + name);
};
lunar.removeClass = function (elem, name) {
var remove = elem.attr('class').replace(new RegExp('(\\s|^)' + name + '(\\s|$)', 'g'), '$2');
lunar.hasClass(elem, name) && elem.attr('class', remove);
};
lunar.toggleClass = function (elem, name) {
lunar[lunar.hasClass(elem, name) ? 'removeClass' : 'addClass'](elem, name);
};
lunar.className = function (elem, name) {
elem.attr('class', name);
console.log('className', elem);
};
return lunar;
});
(function ($) {
var _ = {
cursorPoint: function (evt, el) {
_.settings.pt.x = evt.clientX;
_.settings.pt.y = evt.clientY;
var playObject = el.find('svg').attr('id');
playObject = document.getElementById(playObject);
return _.settings.pt.matrixTransform(playObject.getScreenCTM().inverse());
},
angle: function (ex, ey) {
var dy = ey - 50; // 100;
var dx = ex - 50; // 100;
var theta = Math.atan2(dy, dx); // range (-PI, PI]
theta *= 180 / Math.PI; // rads to degs, range (-180, 180]
theta = theta + 90; // in our case we are animating from the top, so we offset by the rotation value;
if (theta < 0) theta = 360 + theta; // range [0, 360)
return theta;
},
setGraphValue: function (obj, val, el) {
var audioObj = el.find(_.settings.audioObj),
pc = _.settings.pc,
dash = pc - parseFloat(((val / audioObj[0].duration) * pc), 10);
$(obj).css('strokeDashoffset', dash);
if (val === 0) {
$(obj).addClass(obj, 'done');
if (obj === $(_.settings.progress)) $(obj).attr('class', 'ended');
}
},
reportPosition: function (el, audioId) {
var progress = el.find(_.settings.progress),
audio = el.find(_.settings.audioObj);
_.setGraphValue(progress, audioId.currentTime, el);
},
stopAllSounds: function () {
document.addEventListener('play', function (e) {
var audios = document.getElementsByTagName('audio');
for (var i = 0, len = audios.length; i < len; i++) {
if (audios[i] != e.target) {
audios[i].pause();
}
if (audios[i] != e.target) $(audios[i]).parent('div').find('.playing').attr('class', 'paused');
}
}, true);
},
settings: {},
/**
* Main Function for plugin
* @param options
*/
init: function (options) {
/**
* Default Options
*/
var template = ['<svg viewBox="0 0 100 100" id="playable" version="1.1" xmlns="http://www.w3.org/2000/svg" width="34" height="34" data-play="playable" class="not-started playable">',
'<g class="shape">',
'<circle class="progress-track" cx="50" cy="50" r="47.45" stroke="#becce1" stroke-opacity="0.25" stroke-linecap="round" fill="none" stroke-width="5"/>',
'<circle class="precache-bar" cx="50" cy="50" r="47.45" stroke="#302F32" stroke-opacity="0.25" stroke-linecap="round" fill="none" stroke-width="5" transform="rotate(-90 50 50)"/>',
'<circle class="progress-bar" cx="50" cy="50" r="47.45" stroke="#009EF8" stroke-opacity="1" stroke-linecap="round" fill="none" stroke-width="5" transform="rotate(-90 50 50)"/>',
'</g>',
'<circle class="controls" cx="50" cy="50" r="45" stroke="none" fill="#000000" opacity="0.0" pointer-events="all"/>',
'<g class="control pause">',
'<line x1="40" y1="35" x2="40" y2="65" stroke="#000000" fill="none" stroke-width="8" stroke-linecap="round"/>',
'<line x1="60" y1="35" x2="60" y2="65" stroke="#000000" fill="none" stroke-width="8" stroke-linecap="round"/>',
'</g>',
'<g class="control play">',
'<polygon points="45,35 65,50 45,65" fill="#009EF8" stroke-width="0"></polygon>',
'</g>',
'<g class="control stop">',
'<rect x="35" y="35" width="30" height="30" stroke="#000000" fill="none" stroke-width="1"/>',
'</g>',
'</svg>'];
template = template.join(' ');
$.each(this, function (a, b) {
var audio = $(this).find('audio');
audio.attr('id', 'audio' + a);
template = template.replace('width="34"','width="'+ audio.data('size') +'"');
template = template.replace('height="34"','height="'+ audio.data('size') +'"');
template = template.replace('id="playable"', 'id="playable' + a + '"');
$(this).append(template);
});
var svgId = $(this).find('svg').attr('id');
svgId = document.getElementById(svgId);
_.defaults = {
this : this,
thisSelector: this.selector.toString(),
playObj : 'playable',
progress : '.progress-bar',
precache : '.precache-bar',
audioObj : 'audio',
controlsObj : '.controls',
pt : svgId.createSVGPoint(),
pc : 298.1371428256714 // 2 pi r
};
lunar = {};
_.settings = $.extend({}, _.defaults, options);
$(_.settings.controlsObj).on('click', function (e) {
var el = $(e.currentTarget).closest($(_.settings.thisSelector));
var obj = {
el : el,
activeAudio: el.find(_.settings.audioObj),
playObj : el.find('[data-play]'),
precache : el.find(_.settings.precache)
};
obj.class = obj.playObj.attr('class');
switch (obj.class.replace('playable', '').trim()) {
case 'not-started':
_.stopAllSounds();
obj.activeAudio[0].play();
var audioId = document.getElementById(obj.activeAudio.attr('id'));
audioId.addEventListener('timeupdate', function (e) {
_.reportPosition(el, audioId)
});
obj.playObj.attr('class', 'playing');
break;
case 'playing':
obj.playObj.attr('class', 'playable paused');
obj.activeAudio[0].pause();
$(audioId).off('timeupdate');
break;
case 'paused':
obj.playObj.attr('class', 'playable playing');
obj.activeAudio[0].play();
break;
case 'ended':
obj.playObj.attr('class', 'not-started playable');
obj.activeAudio.off('timeupdate', _.reportPosition);
break;
}
});
$(_.defaults.audioObj).on('progress', function (e) {
if (this.buffered.length > 0) {
var end = this.buffered.end(this.buffered.length - 1);
var cache = $(e.currentTarget).parent().find(_.settings.precache),
el = $(this).closest($(_.settings.thisSelector));
_.setGraphValue(cache, end, el);
}
});
}
};
// Add Plugin to Jquery
$.fn.mediaPlayer = function (methodOrOptions) {
if (_[methodOrOptions]) {
return _[methodOrOptions].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof methodOrOptions === 'object' || !methodOrOptions) {
// Default to "init"
return _.init.apply(this, arguments);
} else {
$.error('Method ' + methodOrOptions + ' does not exist on jQuery.mediaPlayer');
}
};
})(jQuery);