/* * jQuery StarRatingSvg v1.2.0 * * http://github.com/nashio/star-rating-svg * Author: Ignacio Chavez * hello@ignaciochavez.com * Licensed under MIT */ ;(function ( $, window, document, undefined ) { 'use strict'; // Create the defaults once var pluginName = 'starRating'; var noop = function(){}; var defaults = { totalStars: 5, useFullStars: false, starShape: 'straight', emptyColor: 'lightgray', hoverColor: '#f1c40f', activeColor: '#f1c40f', ratedColor: '#f1c40f', useGradient: true, readOnly: false, disableAfterRate: true, baseUrl: false, starGradient: { start: '#FEF7CD', end: '#FF9511' }, strokeWidth: 4, strokeColor: 'black', initialRating: 0, starSize: 40, callback: noop, onHover: noop, onLeave: noop }; // The actual plugin constructor var Plugin = function( element, options ) { var _rating; var newRating; var roundFn; this.element = element; this.$el = $(element); this.settings = $.extend( {}, defaults, options ); // grab rating if defined on the element _rating = this.$el.data('rating') || this.settings.initialRating; // round to the nearest half roundFn = this.settings.forceRoundUp ? Math.ceil : Math.round; newRating = (roundFn( _rating * 2 ) / 2).toFixed(1); this._state = { rating: newRating }; // create unique id for stars this._uid = Math.floor( Math.random() * 999 ); // override gradient if not used if( !options.starGradient && !this.settings.useGradient ){ this.settings.starGradient.start = this.settings.starGradient.end = this.settings.activeColor; } this._defaults = defaults; this._name = pluginName; this.init(); }; var methods = { init: function () { this.renderMarkup(); this.addListeners(); this.initRating(); }, addListeners: function(){ if( this.settings.readOnly ){ return; } this.$stars.on('mouseover', this.hoverRating.bind(this)); this.$stars.on('mouseout', this.restoreState.bind(this)); this.$stars.on('click', this.handleRating.bind(this)); }, // apply styles to hovered stars hoverRating: function(e){ var index = this.getIndex(e); this.paintStars(index, 'hovered'); this.settings.onHover(index + 1, this._state.rating, this.$el); }, // clicked on a rate, apply style and state handleRating: function(e){ var index = this.getIndex(e); var rating = index + 1; this.applyRating(rating, this.$el); this.executeCallback( rating, this.$el ); if(this.settings.disableAfterRate){ this.$stars.off(); } }, applyRating: function(rating){ var index = rating - 1; // paint selected and remove hovered color this.paintStars(index, 'rated'); this._state.rating = index + 1; this._state.rated = true; }, restoreState: function(e){ var index = this.getIndex(e); var rating = this._state.rating || -1; // determine star color depending on manually rated var colorType = this._state.rated ? 'rated' : 'active'; this.paintStars(rating - 1, colorType); this.settings.onLeave(index + 1, this._state.rating, this.$el); }, getIndex: function(e){ var $target = $(e.currentTarget); var width = $target.width(); var side = $(e.target).attr('data-side'); var minRating = this.settings.minRating; // hovered outside the star, calculate by pixel instead side = (!side) ? this.getOffsetByPixel(e, $target, width) : side; side = (this.settings.useFullStars) ? 'right' : side ; // get index for half or whole star var index = $target.index() - ((side === 'left') ? 0.5 : 0); // pointer is way to the left, rating should be none index = ( index < 0.5 && (e.offsetX < width / 4) ) ? -1 : index; // force minimum rating index = ( minRating && minRating <= this.settings.totalStars && index < minRating ) ? minRating - 1 : index; return index; }, getOffsetByPixel: function(e, $target, width){ var leftX = e.pageX - $target.offset().left; return ( leftX <= (width / 2) && !this.settings.useFullStars) ? 'left' : 'right'; }, initRating: function(){ this.paintStars(this._state.rating - 1, 'active'); }, paintStars: function(endIndex, stateClass){ var $polygonLeft; var $polygonRight; var leftClass; var rightClass; var s = this.settings; $.each(this.$stars, function(index, star){ $polygonLeft = $(star).find('[data-side="left"]'); $polygonRight = $(star).find('[data-side="right"]'); leftClass = rightClass = (index <= endIndex) ? stateClass : 'empty'; // has another half rating, add half star leftClass = ( index - endIndex === 0.5 ) ? stateClass : leftClass; $polygonLeft.attr('class', 'svg-' + leftClass + '-' + this._uid); $polygonRight.attr('class', 'svg-' + rightClass + '-' + this._uid); // get color for level var ratedColorsIndex = endIndex >= 0 ? Math.ceil(endIndex) : 0; var ratedColor; if (s.ratedColors && s.ratedColors.length && s.ratedColors[ratedColorsIndex]) { ratedColor = s.ratedColors[ratedColorsIndex]; } else { ratedColor = this._defaults.ratedColor; } // only override colors in rated stars and when rated number is valid if (stateClass === 'rated' && endIndex > -1) { // limit to painting only to rated stars, and specific case for half star if (index <= Math.ceil(endIndex) || (index < 1 && endIndex < 0)) { $polygonLeft.attr('style', 'fill:'+ratedColor); } if (index <= endIndex) { $polygonRight.attr('style', 'fill:'+ratedColor); } } }.bind(this)); }, renderMarkup: function () { var s = this.settings; var baseUrl = s.baseUrl ? location.href.split('#')[0] : ''; // inject an svg manually to have control over attributes var star = '
' + this.getLinearGradient(this._uid + '_SVGID_1_', s.emptyColor, s.emptyColor, s.starShape) + this.getLinearGradient(this._uid + '_SVGID_2_', s.hoverColor, s.hoverColor, s.starShape) + this.getLinearGradient(this._uid + '_SVGID_3_', s.starGradient.start, s.starGradient.end, s.starShape) + this.getVectorPath(this._uid, { starShape: s.starShape, strokeWidth: s.strokeWidth, strokeColor: s.strokeColor } ) + '
'; // inject svg markup var starsMarkup = ''; for( var i = 0; i < s.totalStars; i++){ starsMarkup += star; } this.$el.append(starsMarkup); this.$stars = this.$el.find('.jq-star'); }, getVectorPath: function(id, attrs){ return (attrs.starShape === 'rounded') ? this.getRoundedVectorPath(id, attrs) : this.getSpikeVectorPath(id, attrs); }, getSpikeVectorPath: function(id, attrs){ return '' + '' + ''; }, getRoundedVectorPath: function(id, attrs){ var fullPoints = 'M520.9,336.5c-3.8-11.8-14.2-20.5-26.5-22.2l-140.9-20.5l-63-127.7 c-5.5-11.2-16.8-18.2-29.3-18.2c-12.5,0-23.8,7-29.3,18.2l-63,127.7L28,314.2C15.7,316,5.4,324.7,1.6,336.5S1,361.3,9.9,370 l102,99.4l-24,140.3c-2.1,12.3,2.9,24.6,13,32c5.7,4.2,12.4,6.2,19.2,6.2c5.2,0,10.5-1.2,15.2-3.8l126-66.3l126,66.2 c4.8,2.6,10,3.8,15.2,3.8c6.8,0,13.5-2.1,19.2-6.2c10.1-7.3,15.1-19.7,13-32l-24-140.3l102-99.4 C521.6,361.3,524.8,348.3,520.9,336.5z'; return ''; }, getSvgDimensions: function(starShape){ return (starShape === 'rounded') ? 'width="550px" height="500.2px" viewBox="0 146.8 550 500.2" style="enable-background:new 0 0 550 500.2;' : 'x="0px" y="0px" width="305px" height="305px" viewBox="60 -62 309 309" style="enable-background:new 64 -59 305 305;'; }, getLinearGradient: function(id, startColor, endColor, starShape){ var height = (starShape === 'rounded') ? 500 : 250; return ' '; }, executeCallback: function(rating, $el){ var callback = this.settings.callback; callback(rating, $el); } }; var publicMethods = { unload: function() { var _name = 'plugin_' + pluginName; var $el = $(this); var $starSet = $el.data(_name).$stars; $starSet.off(); $el.removeData(_name).remove(); }, setRating: function(rating, round) { var _name = 'plugin_' + pluginName; var $el = $(this); var $plugin = $el.data(_name); if( rating > $plugin.settings.totalStars || rating < 0 ) { return; } if( round ){ rating = Math.round(rating); } $plugin.applyRating(rating); }, getRating: function() { var _name = 'plugin_' + pluginName; var $el = $(this); var $starSet = $el.data(_name); return $starSet._state.rating; }, resize: function(newSize) { var _name = 'plugin_' + pluginName; var $el = $(this); var $starSet = $el.data(_name); var $stars = $starSet.$stars; if(newSize <= 1 || newSize > 200) { console.error('star size out of bounds'); return; } $stars = Array.prototype.slice.call($stars); $stars.forEach(function(star){ $(star).css({ 'width': newSize + 'px', 'height': newSize + 'px' }); }); }, setReadOnly: function(flag) { var _name = 'plugin_' + pluginName; var $el = $(this); var $plugin = $el.data(_name); if(flag === true){ $plugin.$stars.off('mouseover mouseout click'); } else { $plugin.settings.readOnly = false; $plugin.addListeners(); } } }; // Avoid Plugin.prototype conflicts $.extend(Plugin.prototype, methods); $.fn[ pluginName ] = function ( options ) { // if options is a public method if( !$.isPlainObject(options) ){ if( publicMethods.hasOwnProperty(options) ){ return publicMethods[options].apply(this, Array.prototype.slice.call(arguments, 1)); } else { $.error('Method '+ options +' does not exist on ' + pluginName + '.js'); } } return this.each(function() { // preventing against multiple instantiations if ( !$.data( this, 'plugin_' + pluginName ) ) { $.data( this, 'plugin_' + pluginName, new Plugin( this, options ) ); } }); }; })( jQuery, window, document );