gentelella-rtl
Version:
Gentelella RTL Admin is a free to use Bootstrap admin template
642 lines (551 loc) • 17.8 kB
text/coffeescript
# Request Animation Frame Polyfill
# CoffeeScript version of http://paulirish.com/2011/requestanimationframe-for-smart-animating/
do () ->
vendors = ['ms', 'moz', 'webkit', 'o']
for vendor in vendors
if window.requestAnimationFrame
break
window.requestAnimationFrame = window[vendor + 'RequestAnimationFrame']
window.cancelAnimationFrame = window[vendor + 'CancelAnimationFrame'] or window[vendor + 'CancelRequestAnimationFrame']
browserRequestAnimationFrame = null
lastId = 0
isCancelled = {}
if not requestAnimationFrame
window.requestAnimationFrame = (callback, element) ->
currTime = new Date().getTime()
timeToCall = Math.max(0, 16 - (currTime - lastTime))
id = window.setTimeout(() ->
callback(currTime + timeToCall)
, timeToCall)
lastTime = currTime + timeToCall
return id
# This implementation should only be used with the setTimeout()
# version of window.requestAnimationFrame().
window.cancelAnimationFrame = (id) ->
clearTimeout(id)
else if not window.cancelAnimationFrame
browserRequestAnimationFrame = window.requestAnimationFrame
window.requestAnimationFrame = (callback, element) ->
myId = ++lastId
browserRequestAnimationFrame(() ->
if not isCancelled[myId]
callback()
, element)
return myId
window.cancelAnimationFrame = (id) ->
isCancelled[id] = true
secondsToString = (sec) ->
hr = Math.floor(sec / 3600)
min = Math.floor((sec - (hr * 3600))/60)
sec -= ((hr * 3600) + (min * 60))
sec += ''
min += ''
while min.length < 2
min = '0' + min
while sec.length < 2
sec = '0' + sec
hr = if hr then hr + ':' else ''
return hr + min + ':' + sec
formatNumber = (num...) ->
value = num[0]
digits = 0 || num[1]
return addCommas(value.toFixed(digits))
mergeObjects = (obj1, obj2) ->
out = {}
for own key, val of obj1
out[key] = val
for own key, val of obj2
out[key] = val
return out
addCommas = (nStr) ->
nStr += ''
x = nStr.split('.')
x1 = x[0]
x2 = ''
if x.length > 1
x2 = '.' + x[1]
rgx = /(\d+)(\d{3})/
while rgx.test(x1)
x1 = x1.replace(rgx, '$1' + ',' + '$2')
return x1 + x2
cutHex = (nStr) ->
if nStr.charAt(0) == "#"
return nStr.substring(1,7)
return nStr
class ValueUpdater
animationSpeed: 32
constructor: (addToAnimationQueue=true, =true) ->
if addToAnimationQueue
AnimationUpdater.add(@)
update: (force=false) ->
if force or !=
if and
.clearRect(0, 0, .width, .height)
diff = -
if Math.abs(diff / ) <= 0.001
=
else
= + diff /
return true
return false
class BaseGauge extends ValueUpdater
displayScale: 1
forceUpdate: true
setTextField: (textField, fractionDigits) ->
= if textField instanceof TextRenderer then textField else new TextRenderer(textField, fractionDigits)
setMinValue: (, updateStartValue=true) ->
if updateStartValue
=
for gauge in or []
gauge.displayedValue =
setOptions: (options=null) ->
= mergeObjects(, options)
if
.el.style.fontSize = options.fontSize + 'px'
if .angle > .5
.angle = .5
return @
configDisplayScale: () ->
prevDisplayScale =
if .highDpiSupport == false
delete
else
devicePixelRatio = window.devicePixelRatio or 1
backingStorePixelRatio =
.webkitBackingStorePixelRatio or
.mozBackingStorePixelRatio or
.msBackingStorePixelRatio or
.oBackingStorePixelRatio or
.backingStorePixelRatio or 1
= devicePixelRatio / backingStorePixelRatio
if != prevDisplayScale
width = .G__width or .width
height = .G__height or .height
.width = width *
.height = height *
.style.width = "#{width}px"
.style.height = "#{height}px"
.G__width = width
.G__height = height
return @
parseValue: (value) ->
value = parseFloat(value) || Number(value)
return if isFinite(value) then value else 0
class TextRenderer
constructor: (, ) ->
# Default behaviour, override to customize rendering
render: (gauge) ->
.innerHTML = formatNumber(gauge.displayedValue, )
class AnimatedText extends ValueUpdater
displayedValue: 0
value: 0
setVal: (value) ->
= 1 * value
constructor: (, =false) ->
= 1 * .innerHTML
if
= 0
render: () ->
if
textVal = secondsToString(.toFixed(0))
else
textVal = addCommas(formatNumber())
.innerHTML = textVal
AnimatedTextFactory =
create: (objList) ->
out = []
for elem in objList
out.push(new AnimatedText(elem))
return out
class GaugePointer extends ValueUpdater
displayedValue: 0
value: 0
options:
strokeWidth: 0.035
length: 0.1
color: "#000000"
iconPath: null
iconScale: 1.0
iconAngle: 0
img: null
constructor: () ->
= .ctx
= .canvas
super(false, false)
setOptions: (options=null) ->
= mergeObjects(, options)
= 2*.radius * .options.radiusScale * .length
= .height * .strokeWidth
= .maxValue
= .minValue
= .animationSpeed
.angle = .options.angle
if .iconPath
= new Image()
.src = .iconPath
render: () ->
angle = .getAngle.call(@, )
x = Math.round( * Math.cos(angle))
y = Math.round( * Math.sin(angle))
startX = Math.round( * Math.cos(angle - Math.PI/2))
startY = Math.round( * Math.sin(angle - Math.PI/2))
endX = Math.round( * Math.cos(angle + Math.PI/2))
endY = Math.round( * Math.sin(angle + Math.PI/2))
.fillStyle = .color
.beginPath()
.arc(0, 0, , 0, Math.PI*2, true)
.fill()
.beginPath()
.moveTo(startX, startY)
.lineTo(x, y)
.lineTo(endX, endY)
.fill()
if
imgX = Math.round(.width * .iconScale)
imgY = Math.round(.height * .iconScale)
.save()
.translate(x, y)
.rotate(angle + Math.PI/180.0*(90 + .iconAngle))
.drawImage(, -imgX/2, -imgY/2, imgX, imgY)
.restore()
class Bar
constructor: () ->
updateValues: (arrValues) ->
= arrValues[0]
= arrValues[1]
= arrValues[2]
render: () ->
if
.text(formatNumber())
if == 0
= * 2
valPercent = ( / ) * 100
avgPercent = ( / ) * 100
$(".bar-value", ).css({"width": valPercent + "%"})
$(".typical-value", ).css({"width": avgPercent + "%"})
class Gauge extends BaseGauge
elem: null
value: [20] # we support multiple pointers
maxValue: 80
minValue: 0
displayedAngle: 0
displayedValue: 0
lineWidth: 40
paddingTop: 0.1
paddingBottom: 0.1
percentColors: null,
options:
colorStart: "#6fadcf"
colorStop: undefined
gradientType: 0 # 0 : radial, 1 : linear
strokeColor: "#e0e0e0"
pointer:
length: 0.8
strokeWidth: 0.035
iconScale: 1.0
angle: 0.15
lineWidth: 0.44
radiusScale: 1.0
fontSize: 40
limitMax: false
limitMin: false
constructor: () ->
super()
= null
if typeof G_vmlCanvasManager != 'undefined'
= window.G_vmlCanvasManager.initElement()
= .getContext('2d')
# Set canvas size to parent size
h = .clientHeight;
w = .clientWidth;
.height = h;
.width = w;
= [new GaugePointer(@)]
setOptions: (options=null) ->
super(options)
= 0
if .angle < 0
phi = Math.PI*(1 + .angle)
= Math.sin(phi)
= .height * (1 - - )
= * .lineWidth # .2 - .7
= ( - /2) / (1.0 + )
.clearRect(0, 0, .width, .height)
#
for gauge in
gauge.setOptions(.pointer)
gauge.render()
return @
configPercentColors: () ->
= null;
if (.percentColors != undefined)
= new Array()
for i in [0..(.percentColors.length-1)]
rval = parseInt((cutHex(.percentColors[i][1])).substring(0,2),16)
gval = parseInt((cutHex(.percentColors[i][1])).substring(2,4),16)
bval = parseInt((cutHex(.percentColors[i][1])).substring(4,6),16)
[i] = { pct: .percentColors[i][0], color: { r: rval, g: gval, b: bval } }
set: (value) ->
if not (value instanceof Array)
value = [value]
# Ensure values are OK
for i in [0..(value.length-1)]
value[i] =
# check if we have enough GaugePointers initialized
# lazy initialization
if value.length > .length
for i in [0...(value.length - .length)]
gp = new GaugePointer(@)
gp.setOptions(.pointer)
.push(gp)
else if value.length < .length
# Delete redundant GaugePointers
= .slice(.length-value.length)
# get max value and update pointer(s)
i = 0
for val in value
# Limit pointer within min and max?
if val >
if .limitMax
val =
else
= val + 1
else if val <
if .limitMin
val =
else
= val - 1
[i].value = val
[i++].setOptions({minValue: , maxValue: , angle: .angle})
= Math.max(Math.min(value[value.length - 1], ), ) # TODO: Span maybe??
# Force first .set()
AnimationUpdater.run()
= false
getAngle: (value) ->
return (1 + .angle) * Math.PI + ((value - ) / ( - )) * (1 - .angle * 2) * Math.PI
getColorForPercentage: (pct, grad) ->
if pct == 0
color = [0].color;
else
color = [.length - 1].color;
for i in [0..(.length - 1)]
if (pct <= [i].pct)
if grad == true
# Gradually change between colors
startColor = [i - 1] || [0]
endColor = [i]
rangePct = (pct - startColor.pct) / (endColor.pct - startColor.pct) # How far between both colors
color = {
r: Math.floor(startColor.color.r * (1 - rangePct) + endColor.color.r * rangePct),
g: Math.floor(startColor.color.g * (1 - rangePct) + endColor.color.g * rangePct),
b: Math.floor(startColor.color.b * (1 - rangePct) + endColor.color.b * rangePct)
}
else
color = [i].color
break
return 'rgb(' + [color.r, color.g, color.b].join(',') + ')'
getColorForValue: (val, grad) ->
pct = (val - ) / ( - )
return ;
renderStaticLabels: (staticLabels, w, h, radius) ->
.save()
.translate(w, h)
# Scale font size the hard way - assuming size comes first.
font = staticLabels.font or "10px Times"
re = /\d+\.?\d?/
match = font.match(re)[0]
rest = font.slice(match.length);
fontsize = parseFloat(match) * this.displayScale;
.font = fontsize + rest;
.fillStyle = staticLabels.color || "#000000";
.textBaseline = "bottom"
.textAlign = "center"
for value in staticLabels.labels
# Draw labels depending on limitMin/Max
if (not .limitMin or value >= ) and (not .limitMax or value <= )
rotationAngle = - 3*Math.PI/2
.rotate(rotationAngle)
.fillText(formatNumber(value, staticLabels.fractionDigits), 0, -radius - /2)
.rotate(-rotationAngle)
.restore()
render: () ->
# Draw using canvas
w = .width / 2
h = .height* + - ( + /2)*
displayedAngle =
if
.render(@)
.lineCap = "butt"
radius = * .radiusScale
if (.staticLabels)
if (.staticZones)
.save()
.translate(w, h)
.lineWidth =
for zone in .staticZones
# Draw zones depending on limitMin/Max
min = zone.min
if .limitMin and min <
min =
max = zone.max
if .limitMax and max >
max =
.strokeStyle = zone.strokeStyle
.beginPath()
.arc(0, 0, radius, , , false)
.stroke()
.restore()
else
if .customFillStyle != undefined
fillStyle = .customFillStyle(@)
else if != null
fillStyle =
else if .colorStop != undefined
if .gradientType == 0
fillStyle = this.ctx.createRadialGradient(w, h, 9, w, h, 70);
else
fillStyle = this.ctx.createLinearGradient(0, 0, w, 0);
fillStyle.addColorStop(0, .colorStart)
fillStyle.addColorStop(1, .colorStop)
else
fillStyle = .colorStart
.strokeStyle = fillStyle
.beginPath()
.arc(w, h, radius, (1 + .angle) * Math.PI, displayedAngle, false)
.lineWidth =
.stroke()
.strokeStyle = .strokeColor
.beginPath()
.arc(w, h, radius, displayedAngle, (2 - .angle) * Math.PI, false)
.stroke()
# Draw pointers from (w, h)
.translate(w, h)
for gauge in
gauge.update(true)
.translate(-w, -h)
class BaseDonut extends BaseGauge
lineWidth: 15
displayedValue: 0
value: 33
maxValue: 80
minValue: 0
options:
lineWidth: 0.10
colorStart: "#6f6ea0"
colorStop: "#c0c0db"
strokeColor: "#eeeeee"
shadowColor: "#d5d5d5"
angle: 0.35
radiusScale: 1.0
constructor: () ->
super()
if typeof G_vmlCanvasManager != 'undefined'
= window.G_vmlCanvasManager.initElement()
= .getContext('2d')
getAngle: (value) ->
return (1 - .angle) * Math.PI + ((value - ) / ( - )) * ((2 + .angle) - (1 - .angle)) * Math.PI
setOptions: (options=null) ->
super(options)
= .height * .lineWidth
= .radiusScale * (.height / 2 - /2)
return @
set: (value) ->
=
if >
if .limitMax
=
else
=
else if <
if .limitMin
=
else
=
AnimationUpdater.run()
= false
render: () ->
displayedAngle =
w = .width / 2
h = .height / 2
if
.render(@)
grdFill = .createRadialGradient(w, h, 39, w, h, 70)
grdFill.addColorStop(0, .colorStart)
grdFill.addColorStop(1, .colorStop)
start = - / 2
stop = + / 2
.strokeStyle = .strokeColor
.beginPath()
.arc(w, h, , (1 - .angle) * Math.PI, (2 + .angle) * Math.PI, false)
.lineWidth =
.lineCap = "round"
.stroke()
.strokeStyle = grdFill
.beginPath()
.arc(w, h, , (1 - .angle) * Math.PI, displayedAngle, false)
.stroke()
class Donut extends BaseDonut
strokeGradient: (w, h, start, stop) ->
grd = .createRadialGradient(w, h, start, w, h, stop)
grd.addColorStop(0, .shadowColor)
grd.addColorStop(0.12, ._orgStrokeColor)
grd.addColorStop(0.88, ._orgStrokeColor)
grd.addColorStop(1, .shadowColor)
return grd
setOptions: (options=null) ->
super(options)
w = .width / 2
h = .height / 2
start = - / 2
stop = + / 2
._orgStrokeColor = .strokeColor
.strokeColor =
return @
window.AnimationUpdater =
elements: []
animId: null
addAll: (list) ->
for elem in list
AnimationUpdater.elements.push(elem)
add: (object) ->
AnimationUpdater.elements.push(object)
run: (force=false) ->
animationFinished = true
for elem in AnimationUpdater.elements
if elem.update(force is true)
animationFinished = false
if not animationFinished
AnimationUpdater.animId = requestAnimationFrame(AnimationUpdater.run)
else
cancelAnimationFrame(AnimationUpdater.animId)
if typeof window.define == 'function' && window.define.amd?
define(() ->
{
Gauge: Gauge,
Donut: Donut,
BaseDonut: BaseDonut,
TextRenderer: TextRenderer
}
)
else if typeof module != 'undefined' && module.exports?
module.exports = {
Gauge: Gauge,
Donut: Donut,
BaseDonut: BaseDonut,
TextRenderer: TextRenderer
}
else
window.Gauge = Gauge
window.Donut = Donut
window.BaseDonut = BaseDonut
window.TextRenderer = TextRenderer