redline
Version:
Customizable html gauge
287 lines (216 loc) • 7.65 kB
JavaScript
/* !
* Redline
* Cool customizable html gauge
* //github.com/dsblv/redline.js
* by Dmitry Sobolev
*/
//= intro
//= prefix
var _ = {
'nodify': function ( map, selector, parent, prefix ) {
function create ( attributes, prefix ) {
var el = window.document.createElement( attributes.tagName );
if ( attributes.className.length > 0 )
el.className = ( typeof prefix === 'string' ) ?
prefix + '-' + attributes.className :
attributes.className;
return el;
}
function translate ( selector ) {
var info = selector.split('.');
if ( info.length == 1 )
return {
tagName : 'div',
className : info[0]
}
else
return {
tagName : info[0],
className : info[1]
}
}
function isNode ( el ) {
return (typeof el === 'object' &&
typeof el.appendChild === typeof Function);
}
var attributes = translate( selector ),
el;
if ( isNode( parent ) ) {
el = create( attributes, prefix );
parent.appendChild( el );
} else
el = create( attributes );
if ( typeof map === 'object' )
for (node in map)
_.nodify( map[node], node, el, prefix || selector );
else
_.nodify( null, map, el, prefix || selector );
return el;
},
byClass: function ( class, parent ) {
var parent = parent || window.document;
return parent.getElementsByClassName( class )[0] || false;
},
rotate: function ( element, angle ) {
element.style.transform =
element.style[vendorPrefix.lowercase + 'Transform'] = 'rotate(' + angle + 'deg)';
},
addClass: function ( element, className ) {
var classList = element.className.split( ' ' );
if ( classList.indexOf( className ) == -1 )
classList.push( className );
element.className = classList.join( ' ' );
}
}
// Main Redline class
function Redline ( element, options ) {
// default values
var defaults = {
aperture : 260,
marks : [0, 1, 2, 3, 4, 5, 6],
innerMarks : false,
position : 0
}
// DOM elements
this.el = element;
if ( window.jQuery )
this.$el = window.jQuery( this.el );
this.attributes = defaults;
this._extend( options )
._processMarks()
._calculateAngle()
._init();
}
// getter method
Redline.prototype.get = function ( key ) {
return this.attributes[key];
}
// setter method
Redline.prototype.set = function ( key, value ) {
if ( typeof key === 'object' )
return this._extend( key );
this.attributes[key] = value;
return this;
}
// sets multiple values
Redline.prototype._extend = function ( obj ) {
var i = 0;
if ( typeof obj === 'object' )
for ( i in obj )
this.set(i, obj[i]);
return this;
}
// handles marks array
Redline.prototype._processMarks = function ( marks ) {
var marks = marks || this.get( 'marks' );
for ( var index in marks )
if ( typeof marks[index] != 'object' )
marks[index] = { caption: marks[index].toString() };
var length = marks.length;
if ( !marks[length - 2].type )
marks[length - 2].type = 'warning';
if ( !marks[length - 1].type )
marks[length - 1].type = 'danger';
return this;
}
// creates segment
Redline.prototype._createSegment = function ( width, angle, index, loop ) {
var width = width || 0,
angle = angle || 0,
prefix = 'redline-dial-segment',
map = {
'wrap': {
'wrap-wrap': 'line'
},
'mark': {
'mark-wrap': 'span.'
}
},
segment = _.nodify( map, prefix ),
mark = this.get( 'marks' )[index];
// first let's rotate the segment
_.rotate( segment, angle );
// add class to it
if ( typeof mark.type != 'undefined' )
_.addClass( segment, prefix + '-' + mark.type );
// then rotate wraps to acheive desired width
var outer = _.byClass( prefix + '-wrap', segment ),
inner = _.byClass( prefix + '-wrap-wrap', outer ),
caption = _.byClass( prefix + '-mark-wrap', segment );
if ( ( index == 0 || index == this.get( 'marks' ).length - 1 ) && !loop )
_.rotate( inner, -width/2 );
else
_.rotate( inner, -width );
if ( index == ( this.get( 'marks' ).length - 1 ) && !loop )
_.rotate( outer, 0 );
else
_.rotate( outer, width/2 );
// then rotate caption back to horizontal
_.rotate( caption, -angle );
console.log(caption);
// then align ling captions
if ( mark.caption.toString().length > 1 ) {
if ( index < this.get( 'marks' ).length / 2 )
_.addClass( caption, prefix + '-mark-left-fit' );
else
_.addClass( caption, prefix + '-mark-right-fit' );
}
caption.getElementsByTagName( 'span' )[0].innerHTML = mark.caption;
return segment;
}
// calculates actual hand angle
Redline.prototype._calculateAngle = function ( angle, position, getter ) {
var aperture = angle || this.get('aperture'),
position = position || this.get('position'),
noLoop = 1 * ( aperture != 360 ),
percentage = position / ( this.get('marks').length - noLoop );
handAngle = ( 360 - aperture ) / 2 + aperture * percentage;
if ( getter )
return handAngle;
return this.set('handAngle', handAngle);
}
// moves the arrow to specific angle
Redline.prototype.moveHand = function ( angle ) {
var angle = angle || this.get('handAngle');
_.rotate( this.handEl, angle );
return this;
}
// sets angles
Redline.prototype.render = function () {
var aperture = this.get( 'aperture' ),
marks = this.get( 'marks' ),
noLoop = 1 * ( aperture != 360 ),
width = aperture / (marks.length - noLoop);
prefix = 'redline',
map = {
'dial' : null,
'hand' : {
'hand-wrap' : {
'hand-arrow' : null,
'hand-center' : null
}
}
},
redline = _.nodify( map, prefix );
this.el.innerHTML = '';
this.el.appendChild( redline );
this.el = redline;
this.handEl = _.byClass( 'redline-hand-wrap', this.el );
var dial = _.byClass( 'redline-dial', this.el );
for ( var index in marks ) {
angle = this._calculateAngle(null, index, true);
segment = this._createSegment( width, angle, index, aperture == 360 );
console.log(index);
dial.appendChild( segment );
}
if ( this.get( 'innerMarks' ) )
_.addClass( this.el, 'redline-inner-marks' );
return this;
}
Redline.prototype._init = Redline.prototype.render;
Redline.prototype.point = function ( index ) {
return this.set('position', index)
._calculateAngle()
.moveHand();
}
//= outro