Last active
August 29, 2015 14:05
-
-
Save LOZORD/c33f4420d5c18a696bdd to your computer and use it in GitHub Desktop.
Since HTML <progress> bars don't have (non-pseudo) CSS attributes to animate for their width and inner color, I had to break out some nasty JS. Expect an actual library using just vanilla JS some time in the future...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
I used this tutorial below to get some nice looking bars to start out with: | |
http://css-tricks.com/html5-progress-element | |
Some page-specific code has been redacted, only the meat remains | |
Don't blame me if this doesn't compile! This meant for education! | |
*/ | |
const IS_WEBKIT = 'WebkitAppearance' in document.documentElement.style; | |
const RGB_STR_REGEX = /^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/; | |
/* | |
Rounding RGB changes to nearest 10 (faster & less writes) | |
PLEASE make sure that your code (i.e. CSS specifies colors in rgb(x,y,z) format, | |
where x, y, and z are all divisible by 10 | |
*/ | |
const RGB_CHANGE_VELOCITY = 10; | |
const ANIMATE_INTERVAL_PERIOD_TIME = 10; //10 ms | |
/* | |
these are not the true rgb values of these colors, | |
they have been rounded to the nearest 10 for speed | |
*/ | |
const GOOD_COLOR = | |
{ | |
name: 'palegreen', | |
r: 150, | |
g: 250, | |
b: 150 | |
}; | |
const WARN_COLOR = { | |
name: 'gold', | |
r: 260, | |
g: 220, | |
b: 0 | |
}; | |
const BAD_COLOR = { | |
name: 'tomato', | |
r: 220, | |
g: 100, | |
b: 70 | |
}; | |
/* Now set up the add-on CSS file */ | |
//now append a special css style doc for the bar colors | |
var bar_style = document.createElement('style'); | |
document.head.appendChild(bar_style); | |
var bar_color_sheet = bar_style.sheet; | |
//map of (selector -> rule #) in bar_color_sheet | |
bar_color_sheet.selectors = {}; | |
var bar_selectors_count = 0; | |
//this is called from a Ajax promise obj | |
function showData (text, status, jQXHR) | |
{ | |
var data = jQuery.parseJSON(text); | |
var bar_color = calcBarColor(rating.percent, RGB_CHANGE_VELOCITY); | |
var the_guid = data.guid; | |
adjustBar(the_guid, bar_color, rating.percent); | |
} | |
function calcBarColor (perc, round_num, end_is_good) | |
{ | |
//default arguments | |
round_num = typeof round_num === 'undefined' ? 1 : round_num; | |
end_is_good = typeof end_is_good === 'undefined' ? true : end_is_good; | |
//an RGB obj | |
var the_color = {}; | |
var start_color, mid_color, end_color; | |
mid_color = WARN_COLOR; | |
//[bad -> meh -> good] | |
if (end_is_good) | |
{ | |
start_color = BAD_COLOR; | |
end_color = GOOD_COLOR; | |
} | |
//[good -> meh -> bad] | |
else | |
{ | |
start_color = GOOD_COLOR; | |
end_color = BAD_COLOR; | |
} | |
//the first half | |
if (perc < 50) | |
{ | |
//since perc is below 100 | |
var temp = perc * 2; | |
the_color.r = ( start_color.r * (100 - temp)/100 ) + ( mid_color.r * (temp)/100 ); | |
the_color.g = ( start_color.g * (100 - temp)/100 ) + ( mid_color.g * (temp)/100 ); | |
the_color.b = ( start_color.b * (100 - temp)/100 ) + ( mid_color.b * (temp)/100 ); | |
} | |
//the second half | |
else | |
{ | |
//since perc is above 50 | |
var temp = (perc - 50) * 2; | |
the_color.r = ( mid_color.r * (100 - temp)/100 ) + ( end_color.r * (temp)/100 ); | |
the_color.g = ( mid_color.g * (100 - temp)/100 ) + ( end_color.g * (temp)/100 ); | |
the_color.b = ( mid_color.b * (100 - temp)/100 ) + ( end_color.b * (temp)/100 ); | |
} | |
for (var key in the_color) | |
{ | |
//get an integer rounded to the nearest round_num | |
the_color[key] = Math.floor(round_num * Math.round(the_color[key]/round_num)); | |
} | |
return the_color; | |
} | |
function adjustBar(some_guid, some_color, some_perc) | |
{ | |
var device_progress_bar = $('progress#isp_bar_' + some_guid); | |
animatePercentage(device_progress_bar, some_perc); | |
changeBarColor(device_progress_bar, some_color); | |
} | |
//for changing the % or width of the inner bar | |
function animatePercentage(some_bar, some_perc) | |
{ | |
var begin_perc = parseFloat(some_bar.attr('value')); | |
var dist = Math.abs(some_perc - begin_perc); | |
var dir = getDir(begin_perc, some_perc); | |
//for animation | |
function frame () | |
{ | |
if (parseInt(some_bar.attr('value'), 10) === parseInt(some_perc, 10)) | |
{ | |
clearInterval(id); | |
} | |
else | |
{ | |
var curr_perc = parseFloat(some_bar.attr('value')); | |
some_bar.attr('value', (curr_perc + dir).toString()); | |
} | |
} | |
var id = setInterval(frame, ANIMATE_INTERVAL_PERIOD_TIME); | |
} | |
//I basically wanted to implement Ruby's <=> (spaceship/UFO/compare-to) operator | |
function getDir (old_val, new_val) | |
{ | |
if (old_val < new_val) | |
{ | |
return 1; | |
} | |
else if (old_val > new_val) | |
{ | |
return -1; | |
} | |
else | |
{ | |
return 0; | |
} | |
} | |
function getRGBDirObj (old_rgb, new_rgb, vel) | |
{ | |
//default arg, used to speed up change | |
vel = typeof vel === 'undefined' ? 1 : vel; | |
return { | |
r: getDir(old_rgb.r, new_rgb.r) * vel, | |
g: getDir(old_rgb.g, new_rgb.g) * vel, | |
b: getDir(old_rgb.b, new_rgb.b) * vel | |
}; | |
} | |
function changeBarColor(some_bar, some_rgb_obj) | |
{ | |
var the_guid = some_bar.attr('id'); | |
var begin_rgb_obj = rgbStrToRgbObj(getBarColor(the_guid)); | |
var dir_obj = getRGBDirObj(begin_rgb_obj, some_rgb_obj, RGB_CHANGE_VELOCITY); | |
//for animation | |
function frame () | |
{ | |
var curr_color = rgbStrToRgbObj(getBarColor(the_guid)); | |
if (rgbEquality(curr_color, some_rgb_obj)) | |
{ | |
clearInterval(id); | |
} | |
else | |
{ | |
var update_rgb_obj = { | |
r: curr_color.r + dir_obj.r, | |
g: curr_color.g + dir_obj.g, | |
b: curr_color.b + dir_obj.b | |
}; | |
var update_rgb_str = rgbObjToRgbStr(update_rgb_obj); | |
setBarColorRule(the_guid, update_rgb_str); | |
dir_obj = getRGBDirObj(update_rgb_obj, some_rgb_obj, RGB_CHANGE_VELOCITY); | |
} | |
} | |
var id = setInterval(frame, ANIMATE_INTERVAL_PERIOD_TIME); | |
} | |
//changes CSS pseudo-element value bgcolor attr of bar w/this guid | |
function setBarColorRule(some_guid, some_color) | |
{ | |
var style_num = -1; | |
//if the rule already exists | |
if (bar_color_sheet.selectors.hasOwnProperty(some_guid)) | |
{ | |
style_num = bar_color_sheet.selectors[some_guid]; | |
//then destroy the matched rule | |
bar_color_sheet.removeRule ? | |
bar_color_sheet.removeRule(style_num) : | |
bar_color_sheet.deleteRule(style_num) ; | |
} | |
else | |
{ | |
style_num = bar_selectors_count++; | |
bar_color_sheet.selectors[some_guid] = style_num; | |
} | |
var selector_str = '#' + some_guid; | |
//we can only style webkit and mozilla | |
selector_str += IS_WEBKIT ? '::-webkit-progress-value' : '::-moz-progress-bar'; | |
var bg_clr = '{background-color: ' + some_color + '}'; | |
if (bar_color_sheet.insertRule) | |
{ | |
bar_color_sheet.insertRule(selector_str + ' ' + bg_clr, style_num); | |
} | |
else | |
{ | |
bar_color_sheet.addRule(selector_str, bg_clr, style_num); | |
} | |
} | |
function getBarColor(some_guid) | |
{ | |
if (bar_color_sheet.selectors.hasOwnProperty(some_guid)) | |
{ | |
var rule_num = bar_color_sheet.selectors[some_guid]; | |
return (bar_color_sheet.rules[rule_num].style.backgroundColor); | |
} | |
else | |
{ | |
//the default grey | |
return 'rgb(200, 200, 200)'; | |
} | |
} | |
function rgbStrToRgbObj(rgb_str) | |
{ | |
if (!rgb_str.match(RGB_STR_REGEX)) | |
{ | |
return null; | |
} | |
//remove the 'rgb(' header | |
rgb_str = rgb_str.substring( ( 'rgb(' ).length ); | |
//remove the last ')' | |
rgb_str = rgb_str.substring(0, rgb_str.length -1); | |
var rgb_arr = rgb_str.split(','); | |
return { | |
r: parseInt(rgb_arr[0], 10), | |
g: parseInt(rgb_arr[1], 10), | |
b: parseInt(rgb_arr[2], 10) | |
}; | |
} | |
function rgbObjToRgbStr(rgb_obj) | |
{ | |
return ( 'rgb(' + rgb_obj.r + ',' + rgb_obj.g + ',' + rgb_obj.b + ')' ); | |
} | |
function rgbEquality(ob1, ob2) | |
{ | |
return ( | |
ob1.r === ob2.r && | |
ob1.g === ob2.g && | |
ob1.b === ob2.b | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment