diff --git a/examples/area.html b/examples/area.html
index c3c71f5..e5ee6c5 100644
--- a/examples/area.html
+++ b/examples/area.html
@@ -7,6 +7,7 @@
+
Area charts
diff --git a/examples/bar-colors.html b/examples/bar-colors.html
index 95f1d72..c4700ec 100644
--- a/examples/bar-colors.html
+++ b/examples/bar-colors.html
@@ -7,6 +7,7 @@
+
Bar charts
diff --git a/examples/bar.html b/examples/bar.html
index 2209fa7..f3ff842 100644
--- a/examples/bar.html
+++ b/examples/bar.html
@@ -7,6 +7,7 @@
+
Bar charts
diff --git a/examples/days.html b/examples/days.html
index 2c1d5d9..17d0339 100644
--- a/examples/days.html
+++ b/examples/days.html
@@ -7,6 +7,7 @@
+
Formatting Dates YYYY-MM-DD
diff --git a/examples/decimal.html b/examples/decimal.html
index 3a93cf5..331735b 100644
--- a/examples/decimal.html
+++ b/examples/decimal.html
@@ -7,6 +7,7 @@
+
Decimal Data
diff --git a/examples/donut-formatter.html b/examples/donut-formatter.html
index 0df7c06..294db89 100644
--- a/examples/donut-formatter.html
+++ b/examples/donut-formatter.html
@@ -7,6 +7,7 @@
+
Donut Chart
diff --git a/examples/donut.html b/examples/donut.html
index 752a047..a9b51ae 100644
--- a/examples/donut.html
+++ b/examples/donut.html
@@ -7,6 +7,7 @@
+
Donut Chart
diff --git a/examples/events.html b/examples/events.html
index 3d8cad5..933af52 100644
--- a/examples/events.html
+++ b/examples/events.html
@@ -7,6 +7,7 @@
+
Time Events
diff --git a/examples/goals.html b/examples/goals.html
index 3e3b19d..1922db8 100644
--- a/examples/goals.html
+++ b/examples/goals.html
@@ -7,6 +7,7 @@
+
Value Goals
diff --git a/examples/months-no-smooth.html b/examples/months-no-smooth.html
index 95d4788..6e2cd3a 100644
--- a/examples/months-no-smooth.html
+++ b/examples/months-no-smooth.html
@@ -7,6 +7,7 @@
+
Formatting Dates with YYYY-MM
diff --git a/examples/negative.html b/examples/negative.html
index d1ee1a2..b495b9f 100644
--- a/examples/negative.html
+++ b/examples/negative.html
@@ -7,6 +7,7 @@
+
Negative values
diff --git a/examples/non-continuous.html b/examples/non-continuous.html
index e314850..5689772 100644
--- a/examples/non-continuous.html
+++ b/examples/non-continuous.html
@@ -7,6 +7,7 @@
+
Non-continuous data
diff --git a/examples/non-date.html b/examples/non-date.html
index fe34d6e..41e56d4 100644
--- a/examples/non-date.html
+++ b/examples/non-date.html
@@ -7,6 +7,7 @@
+
Formatting Non-date Arbitrary X-axis
diff --git a/examples/quarters.html b/examples/quarters.html
index 67b2212..366cfd6 100644
--- a/examples/quarters.html
+++ b/examples/quarters.html
@@ -7,6 +7,7 @@
+
Formatting Dates with Quarters
diff --git a/examples/timestamps.html b/examples/timestamps.html
index 0db051d..f4d701b 100644
--- a/examples/timestamps.html
+++ b/examples/timestamps.html
@@ -7,6 +7,7 @@
+
Timestamps
diff --git a/examples/updating.html b/examples/updating.html
index 9f757d4..dfaf69e 100644
--- a/examples/updating.html
+++ b/examples/updating.html
@@ -7,6 +7,7 @@
+
Updating data
diff --git a/examples/weeks.html b/examples/weeks.html
index 0e3943f..a8d5d3e 100644
--- a/examples/weeks.html
+++ b/examples/weeks.html
@@ -7,6 +7,7 @@
+
Formatting Dates With Weeks
diff --git a/examples/years.html b/examples/years.html
index 33e973b..fd9d9f7 100644
--- a/examples/years.html
+++ b/examples/years.html
@@ -7,6 +7,7 @@
+
Formatting Dates YYYY
diff --git a/grunt.js b/grunt.js
index 8bee7a4..494e69a 100644
--- a/grunt.js
+++ b/grunt.js
@@ -16,6 +16,7 @@ module.exports = function (grunt) {
'build/morris.coffee': [
'lib/morris.coffee',
'lib/morris.grid.coffee',
+ 'lib/morris.hover.coffee',
'lib/morris.line.coffee',
'lib/morris.area.coffee',
'lib/morris.bar.coffee',
@@ -23,6 +24,15 @@ module.exports = function (grunt) {
],
'build/spec.coffee': ['spec/support/**/*.coffee', 'spec/lib/**/*.coffee']
},
+ less: {
+ all: {
+ src: 'less/*.less',
+ dest: 'morris.css',
+ options: {
+ compress: true
+ }
+ }
+ },
min: {
'morris.min.js': 'morris.js'
},
@@ -33,13 +43,14 @@ module.exports = function (grunt) {
}
},
watch: {
- files: ['lib/**/*.coffee', 'spec/lib/**/*.coffee', 'spec/support/**/*.coffee'],
+ files: ['lib/**/*.coffee', 'spec/lib/**/*.coffee', 'spec/support/**/*.coffee', 'less/**/*.less'],
tasks: 'default'
}
});
grunt.loadNpmTasks('grunt-coffee');
grunt.loadNpmTasks('grunt-mocha');
+ grunt.loadNpmTasks('grunt-less');
- grunt.registerTask('default', 'concat coffee min mocha');
+ grunt.registerTask('default', 'concat coffee less min mocha');
};
diff --git a/less/morris.core.less b/less/morris.core.less
new file mode 100644
index 0000000..02f089e
--- /dev/null
+++ b/less/morris.core.less
@@ -0,0 +1,19 @@
+div.morris-popup {
+ border-radius: 10px;
+ position: absolute;
+ z-index: 1000;
+ padding: 6px;
+ font: normal 13px/16px Arial, sans-serif;
+ color: #666;
+ background: rgba(255,255,255,.8);
+ border: solid 2px rgba(230,230,230,.8);
+
+ h4, p {
+ font: normal 13px/16px Arial, sans-serif;
+ text-align: center;
+ color: #666;
+ margin: 0;
+ }
+
+ h4 { font-weight: bold; }
+}
\ No newline at end of file
diff --git a/lib/morris.area.coffee b/lib/morris.area.coffee
index 53b8130..819ef8c 100644
--- a/lib/morris.area.coffee
+++ b/lib/morris.area.coffee
@@ -31,7 +31,7 @@ class Morris.Area extends Morris.Line
super()
fillForSeries: (i) ->
- color = Raphael.rgb2hsl @colorForSeries(i)
+ color = Raphael.rgb2hsl @colorFor(@data[i], i, 'line')
Raphael.hsl(
color.h,
Math.min(255, color.s * 0.75),
diff --git a/lib/morris.bar.coffee b/lib/morris.bar.coffee
index 518bebe..f8a02cd 100644
--- a/lib/morris.bar.coffee
+++ b/lib/morris.bar.coffee
@@ -1,29 +1,22 @@
class Morris.Bar extends Morris.Grid
- # Initialise the graph.
- #
+ @include Morris.Hover
+
+ # override hoverCalculatePosition
+ hoverGetPosition: (index) ->
+ [x, y] = Morris.Hover.hoverGetPosition.call(this, index)
+
+ [x, (@top + @bottom)/2 - @hoverHeight/2]
+
constructor: (options) ->
return new Morris.Bar(options) unless (@ instanceof Morris.Bar)
super($.extend {}, options, parseTime: false)
- # setup event handlers
- #
init: ->
- @prevHilight = null
- @el.mousemove (evt) =>
- @updateHilight evt.pageX
- if @options.hideHover
- @el.mouseout (evt) =>
- @hilight null
- touchHandler = (evt) =>
- touch = evt.originalEvent.touches[0] or evt.originalEvent.changedTouches[0]
- @updateHilight touch.pageX
- return touch
- @el.bind 'touchstart', touchHandler
- @el.bind 'touchmove', touchHandler
- @el.bind 'touchend', touchHandler
-
- # Default configuration
- #
+ @hoverConfigure @options.hoverOptions
+
+ postInit: ->
+ @hoverInit()
+
defaults:
barSizeRatio: 0.75
barGap: 3
@@ -36,23 +29,13 @@ class Morris.Bar extends Morris.Grid
'#cb4b4b'
'#9440ed'
]
- hoverPaddingX: 10
- hoverPaddingY: 5
- hoverMargin: 10
- hoverFillColor: '#fff'
- hoverBorderColor: '#ccc'
- hoverBorderWidth: 2
- hoverOpacity: 0.95
- hoverLabelColor: '#444'
- hoverFontSize: 12
- hideHover: false
# Do any size-related calculations
#
# @private
calc: ->
@calcBars()
- @calcHoverMargins()
+ @hoverCalculateMargins()
# calculate series data bars coordinates and sizes
#
@@ -63,21 +46,12 @@ class Morris.Bar extends Morris.Grid
row._y = for y in row.y
if y? then @transY(y) else null
- # calculate hover margins
- #
- # @private
- calcHoverMargins: ->
- @hoverMargins = for i in [1...@data.length]
- @left + i * @width / @data.length
-
# Draws the bar chart.
#
draw: ->
@drawXAxis()
@drawSeries()
- @drawHover()
- @hilight(if @options.hideHover then null else @data.length - 1)
-
+
# draw the x-axis labels
#
# @private
@@ -125,69 +99,6 @@ class Morris.Bar extends Morris.Grid
else
null
- # draw the hover tooltip
- #
- # @private
- drawHover: ->
- # hover labels
- @hoverHeight = @options.hoverFontSize * 1.5 * (@options.ykeys.length + 1)
- @hover = @r.rect(-10, -@hoverHeight / 2 - @options.hoverPaddingY, 20, @hoverHeight + @options.hoverPaddingY * 2, 10)
- .attr('fill', @options.hoverFillColor)
- .attr('stroke', @options.hoverBorderColor)
- .attr('stroke-width', @options.hoverBorderWidth)
- .attr('opacity', @options.hoverOpacity)
- @xLabel = @r.text(0, (@options.hoverFontSize * 0.75) - @hoverHeight / 2, '')
- .attr('fill', @options.hoverLabelColor)
- .attr('font-weight', 'bold')
- .attr('font-size', @options.hoverFontSize)
- @hoverSet = @r.set()
- @hoverSet.push(@hover)
- @hoverSet.push(@xLabel)
- @yLabels = []
- for i in [0...@options.ykeys.length]
- yLabel = @r.text(0, @options.hoverFontSize * 1.5 * (i + 1.5) - @hoverHeight / 2, '')
- .attr('font-size', @options.hoverFontSize)
- @yLabels.push(yLabel)
- @hoverSet.push(yLabel)
-
- # @private
- updateHover: (index) =>
- @hoverSet.show()
- row = @data[index]
- @xLabel.attr('text', row.label)
- for y, i in row.y
- @yLabels[i].attr('fill', @colorFor(row, i, 'hover'))
- @yLabels[i].attr('text', "#{@options.labels[i]}: #{@yLabelFormat(y)}")
- # recalculate hover box width
- maxLabelWidth = Math.max.apply null, (l.getBBox().width for l in @yLabels)
- maxLabelWidth = Math.max maxLabelWidth, @xLabel.getBBox().width
- @hover.attr 'width', maxLabelWidth + @options.hoverPaddingX * 2
- @hover.attr 'x', -@options.hoverPaddingX - maxLabelWidth / 2
- # move to y pos
- yloc = (@bottom + @top) / 2
- xloc = Math.min @right - maxLabelWidth / 2 - @options.hoverPaddingX, @data[index]._x
- xloc = Math.max @left + maxLabelWidth / 2 + @options.hoverPaddingX, xloc
- @hoverSet.attr 'transform', "t#{xloc},#{yloc}"
-
- # @private
- hideHover: ->
- @hoverSet.hide()
-
- # @private
- hilight: (index) =>
- if index isnt null and @prevHilight isnt index
- @updateHover index
- @prevHilight = index
- if not index?
- @hideHover()
-
- # @private
- updateHilight: (x) =>
- x -= @el.offset().left
- for hoverIndex in [0...@hoverMargins.length]
- break if @hoverMargins[hoverIndex] > x
- @hilight hoverIndex
-
# @private
#
# @param row [Object] row data
diff --git a/lib/morris.coffee b/lib/morris.coffee
index 87f4d52..8cac223 100644
--- a/lib/morris.coffee
+++ b/lib/morris.coffee
@@ -2,10 +2,27 @@ Morris = window.Morris = {}
$ = jQuery
+# Very simple multiple-inheritance implementation.
+#
+# @private
+class Morris.Module
+ @extend: (obj) ->
+ for key, value of obj when key not in ['extended', 'included']
+ @[key] = value
+
+ obj.extended?.apply(@)
+ this
+
+ @include: (obj) ->
+ for key, value of obj when key not in ['extended', 'included']
+ @::[key] = value
+
+ obj.included?.apply(@)
+
# Very simple event-emitter class.
#
# @private
-class Morris.EventEmitter
+class Morris.EventEmitter extends Morris.Module
on: (name, handler) ->
unless @handlers?
@handlers = {}
@@ -40,3 +57,85 @@ Morris.commas = (num) ->
# @example
# Morris.pad2(1) -> '01'
Morris.pad2 = (number) -> (if number < 10 then '0' else '') + number
+
+# generate a series of label, timestamp pairs for x-axis labels
+#
+# @private
+Morris.labelSeries = (dmin, dmax, pxwidth, specName, xLabelFormat) ->
+ ddensity = 200 * (dmax - dmin) / pxwidth # seconds per `margin` pixels
+ d0 = new Date(dmin)
+ spec = Morris.LABEL_SPECS[specName]
+ # if the spec doesn't exist, search for the closest one in the list
+ if spec is undefined
+ for name in Morris.AUTO_LABEL_ORDER
+ s = Morris.LABEL_SPECS[name]
+ if ddensity >= s.span
+ spec = s
+ break
+ # if we run out of options, use second-intervals
+ if spec is undefined
+ spec = Morris.LABEL_SPECS["second"]
+ # check if there's a user-defined formatting function
+ if xLabelFormat
+ spec = $.extend({}, spec, {fmt: xLabelFormat})
+ # calculate labels
+ d = spec.start(d0)
+ ret = []
+ while (t = d.getTime()) <= dmax
+ if t >= dmin
+ ret.push [spec.fmt(d), t]
+ spec.incr(d)
+ return ret
+
+# @private
+minutesSpecHelper = (interval) ->
+ span: interval * 60 * 1000
+ start: (d) -> new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours())
+ fmt: (d) -> "#{Morris.pad2(d.getHours())}:#{Morris.pad2(d.getMinutes())}"
+ incr: (d) -> d.setMinutes(d.getMinutes() + interval)
+
+# @private
+secondsSpecHelper = (interval) ->
+ span: interval * 1000
+ start: (d) -> new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes())
+ fmt: (d) -> "#{Morris.pad2(d.getHours())}:#{Morris.pad2(d.getMinutes())}:#{Morris.pad2(d.getSeconds())}"
+ incr: (d) -> d.setSeconds(d.getSeconds() + interval)
+
+Morris.LABEL_SPECS =
+ "decade":
+ span: 172800000000 # 10 * 365 * 24 * 60 * 60 * 1000
+ start: (d) -> new Date(d.getFullYear() - d.getFullYear() % 10, 0, 1)
+ fmt: (d) -> "#{d.getFullYear()}"
+ incr: (d) -> d.setFullYear(d.getFullYear() + 10)
+ "year":
+ span: 17280000000 # 365 * 24 * 60 * 60 * 1000
+ start: (d) -> new Date(d.getFullYear(), 0, 1)
+ fmt: (d) -> "#{d.getFullYear()}"
+ incr: (d) -> d.setFullYear(d.getFullYear() + 1)
+ "month":
+ span: 2419200000 # 28 * 24 * 60 * 60 * 1000
+ start: (d) -> new Date(d.getFullYear(), d.getMonth(), 1)
+ fmt: (d) -> "#{d.getFullYear()}-#{Morris.pad2(d.getMonth() + 1)}"
+ incr: (d) -> d.setMonth(d.getMonth() + 1)
+ "day":
+ span: 86400000 # 24 * 60 * 60 * 1000
+ start: (d) -> new Date(d.getFullYear(), d.getMonth(), d.getDate())
+ fmt: (d) -> "#{d.getFullYear()}-#{Morris.pad2(d.getMonth() + 1)}-#{Morris.pad2(d.getDate())}"
+ incr: (d) -> d.setDate(d.getDate() + 1)
+ "hour": minutesSpecHelper(60)
+ "30min": minutesSpecHelper(30)
+ "15min": minutesSpecHelper(15)
+ "10min": minutesSpecHelper(10)
+ "5min": minutesSpecHelper(5)
+ "minute": minutesSpecHelper(1)
+ "30sec": secondsSpecHelper(30)
+ "15sec": secondsSpecHelper(15)
+ "10sec": secondsSpecHelper(10)
+ "5sec": secondsSpecHelper(5)
+ "second": secondsSpecHelper(1)
+
+Morris.AUTO_LABEL_ORDER = [
+ "decade", "year", "month", "day", "hour",
+ "30min", "15min", "10min", "5min", "minute",
+ "30sec", "15sec", "10sec", "5sec", "second"
+]
\ No newline at end of file
diff --git a/lib/morris.grid.coffee b/lib/morris.grid.coffee
index adfce69..8936945 100644
--- a/lib/morris.grid.coffee
+++ b/lib/morris.grid.coffee
@@ -35,6 +35,8 @@ class Morris.Grid extends Morris.EventEmitter
# load data
@setData @options.data
+
+ @postInit() if @postInit
# Default options
#
diff --git a/lib/morris.hover.coffee b/lib/morris.hover.coffee
new file mode 100644
index 0000000..0ccf0e1
--- /dev/null
+++ b/lib/morris.hover.coffee
@@ -0,0 +1,113 @@
+Morris.Hover =
+ hoverConfigure: (options) ->
+ @hoverOptions = $.extend {}, @hoverDefaults, options ? {}
+
+ hoverInit: ->
+ if @hoverOptions.enableHover
+ @hover = @hoverBuild()
+ @hoverBindEvents()
+ @hoverShow(if @hoverOptions.hideHover then null else @data.length - 1)
+
+ hoverDefaults:
+ enableHover: true
+ popupClass: "morris-popup"
+ hideHover: false
+ allowOverflow: false
+ pointMargin: 10
+ hoverFill: (index, row) -> @hoverFill(index, row)
+
+ hoverBindEvents: ->
+ @el.mousemove (evt) =>
+ @hoverUpdate evt.pageX
+ if @hoverOptions.hideHover
+ @el.mouseout (evt) =>
+ @hoverShow null
+ touchHandler = (evt) =>
+ touch = evt.originalEvent.touches[0] or evt.originalEvent.changedTouches[0]
+ @hoverUpdate touch.pageX
+ return touch
+ @el.bind 'touchstart', touchHandler
+ @el.bind 'touchmove', touchHandler
+ @el.bind 'touchend', touchHandler
+
+ @hover.mousemove (evt) -> evt.stopPropagation()
+ @hover.mouseout (evt) -> evt.stopPropagation()
+ @hover.bind 'touchstart', (evt) -> evt.stopPropagation()
+ @hover.bind 'touchmove', (evt) -> evt.stopPropagation()
+ @hover.bind 'touchend', (evt) -> evt.stopPropagation()
+
+ hoverCalculateMargins: ->
+ @hoverMargins = for i in [1...@data.length]
+ @left + i * @width / @data.length
+
+ hoverBuild: ->
+ hover = $ ""
+ hover.addClass "#{@hoverOptions.popupClass} js-morris-popup"
+ hover.appendTo @el
+ hover.hide()
+ hover
+
+ hoverUpdate: (x) ->
+ x -= @el.offset().left
+ for hoverIndex in [0...@hoverMargins.length]
+ break if @hoverMargins[hoverIndex] > x
+ @hoverShow hoverIndex
+
+ hoverShow: (index) ->
+ if index isnt null
+ @hover.html("")
+ @hoverOptions.hoverFill.call(@, index, @data[index])
+ @hoverPosition(index)
+ @fire "hover.show", index
+ @hover.show()
+ if not index?
+ @hoverHide()
+
+ hoverHide: ->
+ @hover.hide()
+
+ colorFor: (row, i, type) -> "inherit"
+ yLabelFormat: (label) -> Morris.commas(label)
+
+ hoverPosition: (index) ->
+ [x, y] = @hoverGetPosition index
+
+ @hover.css
+ top: "#{@el.offset().top + y}px"
+ left: "#{@el.offset().left + x}px"
+
+ hoverGetPosition: (index) ->
+ row = @data[index]
+
+ @hoverWidth = @hover.outerWidth(true)
+ @hoverHeight = @hover.outerHeight(true)
+
+ miny = y = Math.min.apply(null, (y for y in row._y when y isnt null).concat(@bottom))
+
+ x = row._x - @hoverWidth/2
+ y = miny
+ y = y - @hoverHeight - @hoverOptions.pointMargin
+
+ unless @hoverOptions.allowOverflow
+ if x < @left
+ x = row._x + @hoverOptions.pointMargin
+ else if x > @right - @hoverWidth
+ x = row._x - @hoverWidth - @hoverOptions.pointMargin
+
+ y = Math.max y, @top
+ y = Math.min y, (@bottom - @hoverHeight - @hoverOptions.pointMargin)
+
+ if y - miny < @hoverWidth + @hoverOptions.pointMargin
+ y = miny + @hoverOptions.pointMargin
+
+ [x, y]
+
+ hoverFill: (index, row) ->
+ xLabel = $ ""
+ xLabel.text row.label
+ xLabel.appendTo @hover
+ for y, i in row.y
+ yLabel = $ ""
+ yLabel.css "color", @colorFor(row, i, "hover")
+ yLabel.text "#{@options.labels[i]}: #{@yLabelFormat(y)}"
+ yLabel.appendTo @hover
\ No newline at end of file
diff --git a/lib/morris.line.coffee b/lib/morris.line.coffee
index 12c4a90..4a4475e 100644
--- a/lib/morris.line.coffee
+++ b/lib/morris.line.coffee
@@ -1,4 +1,6 @@
class Morris.Line extends Morris.Grid
+ @include Morris.Hover
+
# Initialise the graph.
#
constructor: (options) ->
@@ -9,20 +11,27 @@ class Morris.Line extends Morris.Grid
# Some instance variables for later
@pointGrow = Raphael.animation r: @options.pointSize + 3, 25, 'linear'
@pointShrink = Raphael.animation r: @options.pointSize, 25, 'linear'
+
+ @hoverConfigure @options.hoverOptions
+
# column hilight events
- @prevHilight = null
- @el.mousemove (evt) =>
- @updateHilight evt.pageX
- if @options.hideHover
- @el.mouseout (evt) =>
- @hilight null
- touchHandler = (evt) =>
- touch = evt.originalEvent.touches[0] or evt.originalEvent.changedTouches[0]
- @updateHilight touch.pageX
- return touch
- @el.bind 'touchstart', touchHandler
- @el.bind 'touchmove', touchHandler
- @el.bind 'touchend', touchHandler
+ if @options.hilight
+ @prevHilight = null
+ @el.mousemove (evt) =>
+ @updateHilight evt.pageX
+ if @options.hilightAutoHide
+ @el.mouseout (evt) =>
+ @hilight null
+ touchHandler = (evt) =>
+ touch = evt.originalEvent.touches[0] or evt.originalEvent.changedTouches[0]
+ @updateHilight touch.pageX
+ return touch
+ @el.bind 'touchstart', touchHandler
+ @el.bind 'touchmove', touchHandler
+ @el.bind 'touchend', touchHandler
+
+ postInit: ->
+ @hoverInit()
# Default configuration
#
@@ -41,17 +50,9 @@ class Morris.Line extends Morris.Grid
pointWidths: [1]
pointStrokeColors: ['#ffffff']
pointFillColors: []
- hoverPaddingX: 10
- hoverPaddingY: 5
- hoverMargin: 10
- hoverFillColor: '#fff'
- hoverBorderColor: '#ccc'
- hoverBorderWidth: 2
- hoverOpacity: 0.95
- hoverLabelColor: '#444'
- hoverFontSize: 12
smooth: true
- hideHover: false
+ hilight: true
+ hilightAutoHide: false
xLabels: 'auto'
xLabelFormat: null
@@ -60,8 +61,9 @@ class Morris.Line extends Morris.Grid
# @private
calc: ->
@calcPoints()
+ @hoverCalculateMargins()
@generatePaths()
- @calcHoverMargins()
+ @calcHilightMargins()
# calculate series data point coordinates
#
@@ -72,10 +74,13 @@ class Morris.Line extends Morris.Grid
row._y = for y in row.y
if y? then @transY(y) else null
- # calculate hover margins
+ # calculate hilight margins
#
# @private
- calcHoverMargins: ->
+ calcHilightMargins: ->
+ @hilightMargins = ((r._x + @data[i]._x) / 2 for r, i in @data.slice(1))
+
+ hoverCalculateMargins: ->
@hoverMargins = ((r._x + @data[i]._x) / 2 for r, i in @data.slice(1))
# generate paths for series lines
@@ -95,8 +100,7 @@ class Morris.Line extends Morris.Grid
draw: ->
@drawXAxis()
@drawSeries()
- @drawHover()
- @hilight(if @options.hideHover then null else @data.length - 1)
+ @hilight(if @options.hilightAutoHide then null else @data.length - 1) if @options.hilight
# draw the x-axis labels
#
@@ -140,7 +144,7 @@ class Morris.Line extends Morris.Grid
path = @paths[i]
if path isnt null
@r.path(path)
- .attr('stroke', @colorForSeries(i))
+ .attr('stroke', @colorFor(row, i, 'line'))
.attr('stroke-width', @options.lineWidth)
@seriesPoints = ([] for i in [0...@options.ykeys.length])
for i in [@options.ykeys.length-1..0]
@@ -149,7 +153,7 @@ class Morris.Line extends Morris.Grid
circle = null
else
circle = @r.circle(row._x, row._y[i], @options.pointSize)
- .attr('fill', @pointFillColorForSeries(i) || @colorForSeries(i))
+ .attr('fill', @colorFor(row, i, 'point'))
.attr('stroke-width', @strokeWidthForSeries(i))
.attr('stroke', @strokeForSeries(i))
@seriesPoints[i].push(circle)
@@ -191,61 +195,6 @@ class Morris.Line extends Morris.Grid
else
(coords[i + 1].y - coords[i - 1].y) / (coords[i + 1].x - coords[i - 1].x)
- # draw the hover tooltip
- #
- # @private
- drawHover: ->
- # hover labels
- @hoverHeight = @options.hoverFontSize * 1.5 * (@options.ykeys.length + 1)
- @hover = @r.rect(-10, -@hoverHeight / 2 - @options.hoverPaddingY, 20, @hoverHeight + @options.hoverPaddingY * 2, 10)
- .attr('fill', @options.hoverFillColor)
- .attr('stroke', @options.hoverBorderColor)
- .attr('stroke-width', @options.hoverBorderWidth)
- .attr('opacity', @options.hoverOpacity)
- @xLabel = @r.text(0, (@options.hoverFontSize * 0.75) - @hoverHeight / 2, '')
- .attr('fill', @options.hoverLabelColor)
- .attr('font-weight', 'bold')
- .attr('font-size', @options.hoverFontSize)
- @hoverSet = @r.set()
- @hoverSet.push(@hover)
- @hoverSet.push(@xLabel)
- @yLabels = []
- for i in [0...@options.ykeys.length]
- idx = if @cumulative then (@options.ykeys.length - i - 1) else i
- yLabel = @r.text(0, @options.hoverFontSize * 1.5 * (idx + 1.5) - @hoverHeight / 2, '')
- .attr('fill', @colorForSeries(i))
- .attr('font-size', @options.hoverFontSize)
- @yLabels.push(yLabel)
- @hoverSet.push(yLabel)
-
- # @private
- updateHover: (index) =>
- @hoverSet.show()
- row = @data[index]
- @xLabel.attr('text', row.label)
- for y, i in row.y
- @yLabels[i].attr('text', "#{@options.labels[i]}: #{@yLabelFormat(y)}")
- # recalculate hover box width
- maxLabelWidth = Math.max.apply null, (l.getBBox().width for l in @yLabels)
- maxLabelWidth = Math.max maxLabelWidth, @xLabel.getBBox().width
- @hover.attr 'width', maxLabelWidth + @options.hoverPaddingX * 2
- @hover.attr 'x', -@options.hoverPaddingX - maxLabelWidth / 2
- # move to y pos
- yloc = Math.min.apply null, (y for y in row._y when y isnt null).concat(@bottom)
- if yloc > @hoverHeight + @options.hoverPaddingY * 2 + @options.hoverMargin + @top
- yloc = yloc - @hoverHeight / 2 - @options.hoverPaddingY - @options.hoverMargin
- else
- yloc = yloc + @hoverHeight / 2 + @options.hoverPaddingY + @options.hoverMargin
- yloc = Math.max @top + @hoverHeight / 2 + @options.hoverPaddingY, yloc
- yloc = Math.min @bottom - @hoverHeight / 2 - @options.hoverPaddingY, yloc
- xloc = Math.min @right - maxLabelWidth / 2 - @options.hoverPaddingX, @data[index]._x
- xloc = Math.max @left + maxLabelWidth / 2 + @options.hoverPaddingX, xloc
- @hoverSet.attr 'transform', "t#{xloc},#{yloc}"
-
- # @private
- hideHover: ->
- @hoverSet.hide()
-
# @private
hilight: (index) =>
if @prevHilight isnt null and @prevHilight isnt index
@@ -256,21 +205,14 @@ class Morris.Line extends Morris.Grid
for i in [0..@seriesPoints.length-1]
if @seriesPoints[i][index]
@seriesPoints[i][index].animate @pointGrow
- @updateHover index
@prevHilight = index
- if not index?
- @hideHover()
# @private
updateHilight: (x) =>
x -= @el.offset().left
- for hoverIndex in [0...@hoverMargins.length]
- break if @hoverMargins[hoverIndex] > x
- @hilight hoverIndex
-
- # @private
- colorForSeries: (index) ->
- @options.lineColors[index % @options.lineColors.length]
+ for hilightIndex in [0...@hilightMargins.length]
+ break if @hilightMargins[hilightIndex] > x
+ @hilight hilightIndex
# @private
strokeWidthForSeries: (index) ->
@@ -280,89 +222,10 @@ class Morris.Line extends Morris.Grid
strokeForSeries: (index) ->
@options.pointStrokeColors[index % @options.pointStrokeColors.length]
- # @private
- pointFillColorForSeries: (index) ->
- @options.pointFillColors[index % @options.pointFillColors.length]
-
-
-# generate a series of label, timestamp pairs for x-axis labels
-#
-# @private
-Morris.labelSeries = (dmin, dmax, pxwidth, specName, xLabelFormat) ->
- ddensity = 200 * (dmax - dmin) / pxwidth # seconds per `margin` pixels
- d0 = new Date(dmin)
- spec = Morris.LABEL_SPECS[specName]
- # if the spec doesn't exist, search for the closest one in the list
- if spec is undefined
- for name in Morris.AUTO_LABEL_ORDER
- s = Morris.LABEL_SPECS[name]
- if ddensity >= s.span
- spec = s
- break
- # if we run out of options, use second-intervals
- if spec is undefined
- spec = Morris.LABEL_SPECS["second"]
- # check if there's a user-defined formatting function
- if xLabelFormat
- spec = $.extend({}, spec, {fmt: xLabelFormat})
- # calculate labels
- d = spec.start(d0)
- ret = []
- while (t = d.getTime()) <= dmax
- if t >= dmin
- ret.push [spec.fmt(d), t]
- spec.incr(d)
- return ret
-
-# @private
-minutesSpecHelper = (interval) ->
- span: interval * 60 * 1000
- start: (d) -> new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours())
- fmt: (d) -> "#{Morris.pad2(d.getHours())}:#{Morris.pad2(d.getMinutes())}"
- incr: (d) -> d.setMinutes(d.getMinutes() + interval)
-
-# @private
-secondsSpecHelper = (interval) ->
- span: interval * 1000
- start: (d) -> new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes())
- fmt: (d) -> "#{Morris.pad2(d.getHours())}:#{Morris.pad2(d.getMinutes())}:#{Morris.pad2(d.getSeconds())}"
- incr: (d) -> d.setSeconds(d.getSeconds() + interval)
-
-Morris.LABEL_SPECS =
- "decade":
- span: 172800000000 # 10 * 365 * 24 * 60 * 60 * 1000
- start: (d) -> new Date(d.getFullYear() - d.getFullYear() % 10, 0, 1)
- fmt: (d) -> "#{d.getFullYear()}"
- incr: (d) -> d.setFullYear(d.getFullYear() + 10)
- "year":
- span: 17280000000 # 365 * 24 * 60 * 60 * 1000
- start: (d) -> new Date(d.getFullYear(), 0, 1)
- fmt: (d) -> "#{d.getFullYear()}"
- incr: (d) -> d.setFullYear(d.getFullYear() + 1)
- "month":
- span: 2419200000 # 28 * 24 * 60 * 60 * 1000
- start: (d) -> new Date(d.getFullYear(), d.getMonth(), 1)
- fmt: (d) -> "#{d.getFullYear()}-#{Morris.pad2(d.getMonth() + 1)}"
- incr: (d) -> d.setMonth(d.getMonth() + 1)
- "day":
- span: 86400000 # 24 * 60 * 60 * 1000
- start: (d) -> new Date(d.getFullYear(), d.getMonth(), d.getDate())
- fmt: (d) -> "#{d.getFullYear()}-#{Morris.pad2(d.getMonth() + 1)}-#{Morris.pad2(d.getDate())}"
- incr: (d) -> d.setDate(d.getDate() + 1)
- "hour": minutesSpecHelper(60)
- "30min": minutesSpecHelper(30)
- "15min": minutesSpecHelper(15)
- "10min": minutesSpecHelper(10)
- "5min": minutesSpecHelper(5)
- "minute": minutesSpecHelper(1)
- "30sec": secondsSpecHelper(30)
- "15sec": secondsSpecHelper(15)
- "10sec": secondsSpecHelper(10)
- "5sec": secondsSpecHelper(5)
- "second": secondsSpecHelper(1)
-
-Morris.AUTO_LABEL_ORDER = [
- "decade", "year", "month", "day", "hour",
- "30min", "15min", "10min", "5min", "minute",
- "30sec", "15sec", "10sec", "5sec", "second"
-]
+ colorFor: (row, sidx, type) ->
+ if typeof @options.lineColors is 'function'
+ @options.lineColors.call(@, row, sidx, type)
+ else if type is 'point'
+ @options.pointFillColors[sidx % @options.pointFillColors.length] || @options.lineColors[sidx % @options.lineColors.length]
+ else
+ @options.lineColors[sidx % @options.lineColors.length]
\ No newline at end of file
diff --git a/morris.css b/morris.css
new file mode 100644
index 0000000..d2ff85b
--- /dev/null
+++ b/morris.css
@@ -0,0 +1,2 @@
+div.morris-popup{border-radius:10px;position:absolute;z-index:1000;padding:6px;font:normal 13px/16px Arial,sans-serif;color:#666;background:rgba(255, 255, 255, 0.8);border:solid 2px rgba(230, 230, 230, 0.8);}div.morris-popup h4,div.morris-popup p{font:normal 13px/16px Arial,sans-serif;text-align:center;color:#666;margin:0;}
+div.morris-popup h4{font-weight:bold;}
diff --git a/morris.js b/morris.js
index 54e432d..d3e4f1f 100644
--- a/morris.js
+++ b/morris.js
@@ -1,8 +1,8 @@
(function() {
var $, Morris, minutesSpecHelper, secondsSpecHelper,
- __slice = [].slice,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+ __slice = [].slice,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
@@ -10,9 +10,46 @@
$ = jQuery;
- Morris.EventEmitter = (function() {
+ Morris.Module = (function() {
- function EventEmitter() {}
+ function Module() {}
+
+ Module.extend = function(obj) {
+ var key, value, _ref;
+ for (key in obj) {
+ value = obj[key];
+ if (key !== 'extended' && key !== 'included') {
+ this[key] = value;
+ }
+ }
+ if ((_ref = obj.extended) != null) {
+ _ref.apply(this);
+ }
+ return this;
+ };
+
+ Module.include = function(obj) {
+ var key, value, _ref;
+ for (key in obj) {
+ value = obj[key];
+ if (key !== 'extended' && key !== 'included') {
+ this.prototype[key] = value;
+ }
+ }
+ return (_ref = obj.included) != null ? _ref.apply(this) : void 0;
+ };
+
+ return Module;
+
+ })();
+
+ Morris.EventEmitter = (function(_super) {
+
+ __extends(EventEmitter, _super);
+
+ function EventEmitter() {
+ return EventEmitter.__super__.constructor.apply(this, arguments);
+ }
EventEmitter.prototype.on = function(name, handler) {
if (this.handlers == null) {
@@ -40,7 +77,7 @@
return EventEmitter;
- })();
+ })(Morris.Module);
Morris.commas = function(num) {
var absnum, intnum, ret, strabsnum;
@@ -63,6 +100,135 @@
return (number < 10 ? '0' : '') + number;
};
+ Morris.labelSeries = function(dmin, dmax, pxwidth, specName, xLabelFormat) {
+ var d, d0, ddensity, name, ret, s, spec, t, _i, _len, _ref;
+ ddensity = 200 * (dmax - dmin) / pxwidth;
+ d0 = new Date(dmin);
+ spec = Morris.LABEL_SPECS[specName];
+ if (spec === void 0) {
+ _ref = Morris.AUTO_LABEL_ORDER;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ name = _ref[_i];
+ s = Morris.LABEL_SPECS[name];
+ if (ddensity >= s.span) {
+ spec = s;
+ break;
+ }
+ }
+ }
+ if (spec === void 0) {
+ spec = Morris.LABEL_SPECS["second"];
+ }
+ if (xLabelFormat) {
+ spec = $.extend({}, spec, {
+ fmt: xLabelFormat
+ });
+ }
+ d = spec.start(d0);
+ ret = [];
+ while ((t = d.getTime()) <= dmax) {
+ if (t >= dmin) {
+ ret.push([spec.fmt(d), t]);
+ }
+ spec.incr(d);
+ }
+ return ret;
+ };
+
+ minutesSpecHelper = function(interval) {
+ return {
+ span: interval * 60 * 1000,
+ start: function(d) {
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours());
+ },
+ fmt: function(d) {
+ return "" + (Morris.pad2(d.getHours())) + ":" + (Morris.pad2(d.getMinutes()));
+ },
+ incr: function(d) {
+ return d.setMinutes(d.getMinutes() + interval);
+ }
+ };
+ };
+
+ secondsSpecHelper = function(interval) {
+ return {
+ span: interval * 1000,
+ start: function(d) {
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes());
+ },
+ fmt: function(d) {
+ return "" + (Morris.pad2(d.getHours())) + ":" + (Morris.pad2(d.getMinutes())) + ":" + (Morris.pad2(d.getSeconds()));
+ },
+ incr: function(d) {
+ return d.setSeconds(d.getSeconds() + interval);
+ }
+ };
+ };
+
+ Morris.LABEL_SPECS = {
+ "decade": {
+ span: 172800000000,
+ start: function(d) {
+ return new Date(d.getFullYear() - d.getFullYear() % 10, 0, 1);
+ },
+ fmt: function(d) {
+ return "" + (d.getFullYear());
+ },
+ incr: function(d) {
+ return d.setFullYear(d.getFullYear() + 10);
+ }
+ },
+ "year": {
+ span: 17280000000,
+ start: function(d) {
+ return new Date(d.getFullYear(), 0, 1);
+ },
+ fmt: function(d) {
+ return "" + (d.getFullYear());
+ },
+ incr: function(d) {
+ return d.setFullYear(d.getFullYear() + 1);
+ }
+ },
+ "month": {
+ span: 2419200000,
+ start: function(d) {
+ return new Date(d.getFullYear(), d.getMonth(), 1);
+ },
+ fmt: function(d) {
+ return "" + (d.getFullYear()) + "-" + (Morris.pad2(d.getMonth() + 1));
+ },
+ incr: function(d) {
+ return d.setMonth(d.getMonth() + 1);
+ }
+ },
+ "day": {
+ span: 86400000,
+ start: function(d) {
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate());
+ },
+ fmt: function(d) {
+ return "" + (d.getFullYear()) + "-" + (Morris.pad2(d.getMonth() + 1)) + "-" + (Morris.pad2(d.getDate()));
+ },
+ incr: function(d) {
+ return d.setDate(d.getDate() + 1);
+ }
+ },
+ "hour": minutesSpecHelper(60),
+ "30min": minutesSpecHelper(30),
+ "15min": minutesSpecHelper(15),
+ "10min": minutesSpecHelper(10),
+ "5min": minutesSpecHelper(5),
+ "minute": minutesSpecHelper(1),
+ "30sec": secondsSpecHelper(30),
+ "15sec": secondsSpecHelper(15),
+ "10sec": secondsSpecHelper(10),
+ "5sec": secondsSpecHelper(5),
+ "second": secondsSpecHelper(1)
+ };
+
+ Morris.AUTO_LABEL_ORDER = ["decade", "year", "month", "day", "hour", "30min", "15min", "10min", "5min", "minute", "30sec", "15sec", "10sec", "5sec", "second"];
+
Morris.Grid = (function(_super) {
__extends(Grid, _super);
@@ -91,6 +257,9 @@
this.init();
}
this.setData(this.options.data);
+ if (this.postInit) {
+ this.postInit();
+ }
}
Grid.prototype.gridDefaults = {
@@ -420,16 +589,183 @@
}
};
+ Morris.Hover = {
+ hoverConfigure: function(options) {
+ return this.hoverOptions = $.extend({}, this.hoverDefaults, options != null ? options : {});
+ },
+ hoverInit: function() {
+ if (this.hoverOptions.enableHover) {
+ this.hover = this.hoverBuild();
+ this.hoverBindEvents();
+ return this.hoverShow(this.hoverOptions.hideHover ? null : this.data.length - 1);
+ }
+ },
+ hoverDefaults: {
+ enableHover: true,
+ popupClass: "morris-popup",
+ hideHover: false,
+ allowOverflow: false,
+ pointMargin: 10,
+ hoverFill: function(index, row) {
+ return this.hoverFill(index, row);
+ }
+ },
+ hoverBindEvents: function() {
+ var touchHandler,
+ _this = this;
+ this.el.mousemove(function(evt) {
+ return _this.hoverUpdate(evt.pageX);
+ });
+ if (this.hoverOptions.hideHover) {
+ this.el.mouseout(function(evt) {
+ return _this.hoverShow(null);
+ });
+ }
+ touchHandler = function(evt) {
+ var touch;
+ touch = evt.originalEvent.touches[0] || evt.originalEvent.changedTouches[0];
+ _this.hoverUpdate(touch.pageX);
+ return touch;
+ };
+ this.el.bind('touchstart', touchHandler);
+ this.el.bind('touchmove', touchHandler);
+ this.el.bind('touchend', touchHandler);
+ this.hover.mousemove(function(evt) {
+ return evt.stopPropagation();
+ });
+ this.hover.mouseout(function(evt) {
+ return evt.stopPropagation();
+ });
+ this.hover.bind('touchstart', function(evt) {
+ return evt.stopPropagation();
+ });
+ this.hover.bind('touchmove', function(evt) {
+ return evt.stopPropagation();
+ });
+ return this.hover.bind('touchend', function(evt) {
+ return evt.stopPropagation();
+ });
+ },
+ hoverCalculateMargins: function() {
+ var i;
+ return this.hoverMargins = (function() {
+ var _i, _ref, _results;
+ _results = [];
+ for (i = _i = 1, _ref = this.data.length; 1 <= _ref ? _i < _ref : _i > _ref; i = 1 <= _ref ? ++_i : --_i) {
+ _results.push(this.left + i * this.width / this.data.length);
+ }
+ return _results;
+ }).call(this);
+ },
+ hoverBuild: function() {
+ var hover;
+ hover = $("");
+ hover.addClass("" + this.hoverOptions.popupClass + " js-morris-popup");
+ hover.appendTo(this.el);
+ hover.hide();
+ return hover;
+ },
+ hoverUpdate: function(x) {
+ var hoverIndex, _i, _ref;
+ x -= this.el.offset().left;
+ for (hoverIndex = _i = 0, _ref = this.hoverMargins.length; 0 <= _ref ? _i < _ref : _i > _ref; hoverIndex = 0 <= _ref ? ++_i : --_i) {
+ if (this.hoverMargins[hoverIndex] > x) {
+ break;
+ }
+ }
+ return this.hoverShow(hoverIndex);
+ },
+ hoverShow: function(index) {
+ if (index !== null) {
+ this.hover.html("");
+ this.hoverOptions.hoverFill.call(this, index, this.data[index]);
+ this.hoverPosition(index);
+ this.fire("hover.show", index);
+ this.hover.show();
+ }
+ if (!(index != null)) {
+ return this.hoverHide();
+ }
+ },
+ hoverHide: function() {
+ return this.hover.hide();
+ },
+ colorFor: function(row, i, type) {
+ return "inherit";
+ },
+ yLabelFormat: function(label) {
+ return Morris.commas(label);
+ },
+ hoverPosition: function(index) {
+ var x, y, _ref;
+ _ref = this.hoverGetPosition(index), x = _ref[0], y = _ref[1];
+ return this.hover.css({
+ top: "" + (this.el.offset().top + y) + "px",
+ left: "" + (this.el.offset().left + x) + "px"
+ });
+ },
+ hoverGetPosition: function(index) {
+ var miny, row, x, y;
+ row = this.data[index];
+ this.hoverWidth = this.hover.outerWidth(true);
+ this.hoverHeight = this.hover.outerHeight(true);
+ miny = y = Math.min.apply(null, ((function() {
+ var _i, _len, _ref, _results;
+ _ref = row._y;
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ y = _ref[_i];
+ if (y !== null) {
+ _results.push(y);
+ }
+ }
+ return _results;
+ })()).concat(this.bottom));
+ x = row._x - this.hoverWidth / 2;
+ y = miny;
+ y = y - this.hoverHeight - this.hoverOptions.pointMargin;
+ if (!this.hoverOptions.allowOverflow) {
+ if (x < this.left) {
+ x = row._x + this.hoverOptions.pointMargin;
+ } else if (x > this.right - this.hoverWidth) {
+ x = row._x - this.hoverWidth - this.hoverOptions.pointMargin;
+ }
+ y = Math.max(y, this.top);
+ y = Math.min(y, this.bottom - this.hoverHeight - this.hoverOptions.pointMargin);
+ if (y - miny < this.hoverWidth + this.hoverOptions.pointMargin) {
+ y = miny + this.hoverOptions.pointMargin;
+ }
+ }
+ return [x, y];
+ },
+ hoverFill: function(index, row) {
+ var i, xLabel, y, yLabel, _i, _len, _ref, _results;
+ xLabel = $("");
+ xLabel.text(row.label);
+ xLabel.appendTo(this.hover);
+ _ref = row.y;
+ _results = [];
+ for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
+ y = _ref[i];
+ yLabel = $("");
+ yLabel.css("color", this.colorFor(row, i, "hover"));
+ yLabel.text("" + this.options.labels[i] + ": " + (this.yLabelFormat(y)));
+ _results.push(yLabel.appendTo(this.hover));
+ }
+ return _results;
+ }
+ };
+
Morris.Line = (function(_super) {
__extends(Line, _super);
+ Line.include(Morris.Hover);
+
function Line(options) {
this.updateHilight = __bind(this.updateHilight, this);
this.hilight = __bind(this.hilight, this);
-
- this.updateHover = __bind(this.updateHover, this);
if (!(this instanceof Morris.Line)) {
return new Morris.Line(options);
}
@@ -445,24 +781,31 @@
this.pointShrink = Raphael.animation({
r: this.options.pointSize
}, 25, 'linear');
- this.prevHilight = null;
- this.el.mousemove(function(evt) {
- return _this.updateHilight(evt.pageX);
- });
- if (this.options.hideHover) {
- this.el.mouseout(function(evt) {
- return _this.hilight(null);
+ this.hoverConfigure(this.options.hoverOptions);
+ if (this.options.hilight) {
+ this.prevHilight = null;
+ this.el.mousemove(function(evt) {
+ return _this.updateHilight(evt.pageX);
});
+ if (this.options.hilightAutoHide) {
+ this.el.mouseout(function(evt) {
+ return _this.hilight(null);
+ });
+ }
+ touchHandler = function(evt) {
+ var touch;
+ touch = evt.originalEvent.touches[0] || evt.originalEvent.changedTouches[0];
+ _this.updateHilight(touch.pageX);
+ return touch;
+ };
+ this.el.bind('touchstart', touchHandler);
+ this.el.bind('touchmove', touchHandler);
+ return this.el.bind('touchend', touchHandler);
}
- touchHandler = function(evt) {
- var touch;
- touch = evt.originalEvent.touches[0] || evt.originalEvent.changedTouches[0];
- _this.updateHilight(touch.pageX);
- return touch;
- };
- this.el.bind('touchstart', touchHandler);
- this.el.bind('touchmove', touchHandler);
- return this.el.bind('touchend', touchHandler);
+ };
+
+ Line.prototype.postInit = function() {
+ return this.hoverInit();
};
Line.prototype.defaults = {
@@ -472,25 +815,18 @@
pointWidths: [1],
pointStrokeColors: ['#ffffff'],
pointFillColors: [],
- hoverPaddingX: 10,
- hoverPaddingY: 5,
- hoverMargin: 10,
- hoverFillColor: '#fff',
- hoverBorderColor: '#ccc',
- hoverBorderWidth: 2,
- hoverOpacity: 0.95,
- hoverLabelColor: '#444',
- hoverFontSize: 12,
smooth: true,
- hideHover: false,
+ hilight: true,
+ hilightAutoHide: false,
xLabels: 'auto',
xLabelFormat: null
};
Line.prototype.calc = function() {
this.calcPoints();
+ this.hoverCalculateMargins();
this.generatePaths();
- return this.calcHoverMargins();
+ return this.calcHilightMargins();
};
Line.prototype.calcPoints = function() {
@@ -518,7 +854,21 @@
return _results;
};
- Line.prototype.calcHoverMargins = function() {
+ Line.prototype.calcHilightMargins = function() {
+ var i, r;
+ return this.hilightMargins = (function() {
+ var _i, _len, _ref, _results;
+ _ref = this.data.slice(1);
+ _results = [];
+ for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
+ r = _ref[i];
+ _results.push((r._x + this.data[i]._x) / 2);
+ }
+ return _results;
+ }).call(this);
+ };
+
+ Line.prototype.hoverCalculateMargins = function() {
var i, r;
return this.hoverMargins = (function() {
var _i, _len, _ref, _results;
@@ -567,8 +917,9 @@
Line.prototype.draw = function() {
this.drawXAxis();
this.drawSeries();
- this.drawHover();
- return this.hilight(this.options.hideHover ? null : this.data.length - 1);
+ if (this.options.hilight) {
+ return this.hilight(this.options.hilightAutoHide ? null : this.data.length - 1);
+ }
};
Line.prototype.drawXAxis = function() {
@@ -619,7 +970,7 @@
for (i = _i = _ref = this.options.ykeys.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
path = this.paths[i];
if (path !== null) {
- this.r.path(path).attr('stroke', this.colorForSeries(i)).attr('stroke-width', this.options.lineWidth);
+ this.r.path(path).attr('stroke', this.colorFor(row, i, 'line')).attr('stroke-width', this.options.lineWidth);
}
}
this.seriesPoints = (function() {
@@ -641,7 +992,7 @@
if (row._y[i] === null) {
circle = null;
} else {
- circle = this.r.circle(row._x, row._y[i], this.options.pointSize).attr('fill', this.pointFillColorForSeries(i) || this.colorForSeries(i)).attr('stroke-width', this.strokeWidthForSeries(i)).attr('stroke', this.strokeForSeries(i));
+ circle = this.r.circle(row._x, row._y[i], this.options.pointSize).attr('fill', this.colorFor(row, i, 'point')).attr('stroke-width', this.strokeWidthForSeries(i)).attr('stroke', this.strokeForSeries(i));
}
_results1.push(this.seriesPoints[i].push(circle));
}
@@ -702,76 +1053,6 @@
return _results;
};
- Line.prototype.drawHover = function() {
- var i, idx, yLabel, _i, _ref, _results;
- this.hoverHeight = this.options.hoverFontSize * 1.5 * (this.options.ykeys.length + 1);
- this.hover = this.r.rect(-10, -this.hoverHeight / 2 - this.options.hoverPaddingY, 20, this.hoverHeight + this.options.hoverPaddingY * 2, 10).attr('fill', this.options.hoverFillColor).attr('stroke', this.options.hoverBorderColor).attr('stroke-width', this.options.hoverBorderWidth).attr('opacity', this.options.hoverOpacity);
- this.xLabel = this.r.text(0, (this.options.hoverFontSize * 0.75) - this.hoverHeight / 2, '').attr('fill', this.options.hoverLabelColor).attr('font-weight', 'bold').attr('font-size', this.options.hoverFontSize);
- this.hoverSet = this.r.set();
- this.hoverSet.push(this.hover);
- this.hoverSet.push(this.xLabel);
- this.yLabels = [];
- _results = [];
- for (i = _i = 0, _ref = this.options.ykeys.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
- idx = this.cumulative ? this.options.ykeys.length - i - 1 : i;
- yLabel = this.r.text(0, this.options.hoverFontSize * 1.5 * (idx + 1.5) - this.hoverHeight / 2, '').attr('fill', this.colorForSeries(i)).attr('font-size', this.options.hoverFontSize);
- this.yLabels.push(yLabel);
- _results.push(this.hoverSet.push(yLabel));
- }
- return _results;
- };
-
- Line.prototype.updateHover = function(index) {
- var i, l, maxLabelWidth, row, xloc, y, yloc, _i, _len, _ref;
- this.hoverSet.show();
- row = this.data[index];
- this.xLabel.attr('text', row.label);
- _ref = row.y;
- for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
- y = _ref[i];
- this.yLabels[i].attr('text', "" + this.options.labels[i] + ": " + (this.yLabelFormat(y)));
- }
- maxLabelWidth = Math.max.apply(null, (function() {
- var _j, _len1, _ref1, _results;
- _ref1 = this.yLabels;
- _results = [];
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
- l = _ref1[_j];
- _results.push(l.getBBox().width);
- }
- return _results;
- }).call(this));
- maxLabelWidth = Math.max(maxLabelWidth, this.xLabel.getBBox().width);
- this.hover.attr('width', maxLabelWidth + this.options.hoverPaddingX * 2);
- this.hover.attr('x', -this.options.hoverPaddingX - maxLabelWidth / 2);
- yloc = Math.min.apply(null, ((function() {
- var _j, _len1, _ref1, _results;
- _ref1 = row._y;
- _results = [];
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
- y = _ref1[_j];
- if (y !== null) {
- _results.push(y);
- }
- }
- return _results;
- })()).concat(this.bottom));
- if (yloc > this.hoverHeight + this.options.hoverPaddingY * 2 + this.options.hoverMargin + this.top) {
- yloc = yloc - this.hoverHeight / 2 - this.options.hoverPaddingY - this.options.hoverMargin;
- } else {
- yloc = yloc + this.hoverHeight / 2 + this.options.hoverPaddingY + this.options.hoverMargin;
- }
- yloc = Math.max(this.top + this.hoverHeight / 2 + this.options.hoverPaddingY, yloc);
- yloc = Math.min(this.bottom - this.hoverHeight / 2 - this.options.hoverPaddingY, yloc);
- xloc = Math.min(this.right - maxLabelWidth / 2 - this.options.hoverPaddingX, this.data[index]._x);
- xloc = Math.max(this.left + maxLabelWidth / 2 + this.options.hoverPaddingX, xloc);
- return this.hoverSet.attr('transform', "t" + xloc + "," + yloc);
- };
-
- Line.prototype.hideHover = function() {
- return this.hoverSet.hide();
- };
-
Line.prototype.hilight = function(index) {
var i, _i, _j, _ref, _ref1;
if (this.prevHilight !== null && this.prevHilight !== index) {
@@ -787,27 +1068,19 @@
this.seriesPoints[i][index].animate(this.pointGrow);
}
}
- this.updateHover(index);
- }
- this.prevHilight = index;
- if (!(index != null)) {
- return this.hideHover();
}
+ return this.prevHilight = index;
};
Line.prototype.updateHilight = function(x) {
- var hoverIndex, _i, _ref;
+ var hilightIndex, _i, _ref;
x -= this.el.offset().left;
- for (hoverIndex = _i = 0, _ref = this.hoverMargins.length; 0 <= _ref ? _i < _ref : _i > _ref; hoverIndex = 0 <= _ref ? ++_i : --_i) {
- if (this.hoverMargins[hoverIndex] > x) {
+ for (hilightIndex = _i = 0, _ref = this.hilightMargins.length; 0 <= _ref ? _i < _ref : _i > _ref; hilightIndex = 0 <= _ref ? ++_i : --_i) {
+ if (this.hilightMargins[hilightIndex] > x) {
break;
}
}
- return this.hilight(hoverIndex);
- };
-
- Line.prototype.colorForSeries = function(index) {
- return this.options.lineColors[index % this.options.lineColors.length];
+ return this.hilight(hilightIndex);
};
Line.prototype.strokeWidthForSeries = function(index) {
@@ -818,143 +1091,20 @@
return this.options.pointStrokeColors[index % this.options.pointStrokeColors.length];
};
- Line.prototype.pointFillColorForSeries = function(index) {
- return this.options.pointFillColors[index % this.options.pointFillColors.length];
+ Line.prototype.colorFor = function(row, sidx, type) {
+ if (typeof this.options.lineColors === 'function') {
+ return this.options.lineColors.call(this, row, sidx, type);
+ } else if (type === 'point') {
+ return this.options.pointFillColors[sidx % this.options.pointFillColors.length] || this.options.lineColors[sidx % this.options.lineColors.length];
+ } else {
+ return this.options.lineColors[sidx % this.options.lineColors.length];
+ }
};
return Line;
})(Morris.Grid);
- Morris.labelSeries = function(dmin, dmax, pxwidth, specName, xLabelFormat) {
- var d, d0, ddensity, name, ret, s, spec, t, _i, _len, _ref;
- ddensity = 200 * (dmax - dmin) / pxwidth;
- d0 = new Date(dmin);
- spec = Morris.LABEL_SPECS[specName];
- if (spec === void 0) {
- _ref = Morris.AUTO_LABEL_ORDER;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- name = _ref[_i];
- s = Morris.LABEL_SPECS[name];
- if (ddensity >= s.span) {
- spec = s;
- break;
- }
- }
- }
- if (spec === void 0) {
- spec = Morris.LABEL_SPECS["second"];
- }
- if (xLabelFormat) {
- spec = $.extend({}, spec, {
- fmt: xLabelFormat
- });
- }
- d = spec.start(d0);
- ret = [];
- while ((t = d.getTime()) <= dmax) {
- if (t >= dmin) {
- ret.push([spec.fmt(d), t]);
- }
- spec.incr(d);
- }
- return ret;
- };
-
- minutesSpecHelper = function(interval) {
- return {
- span: interval * 60 * 1000,
- start: function(d) {
- return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours());
- },
- fmt: function(d) {
- return "" + (Morris.pad2(d.getHours())) + ":" + (Morris.pad2(d.getMinutes()));
- },
- incr: function(d) {
- return d.setMinutes(d.getMinutes() + interval);
- }
- };
- };
-
- secondsSpecHelper = function(interval) {
- return {
- span: interval * 1000,
- start: function(d) {
- return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes());
- },
- fmt: function(d) {
- return "" + (Morris.pad2(d.getHours())) + ":" + (Morris.pad2(d.getMinutes())) + ":" + (Morris.pad2(d.getSeconds()));
- },
- incr: function(d) {
- return d.setSeconds(d.getSeconds() + interval);
- }
- };
- };
-
- Morris.LABEL_SPECS = {
- "decade": {
- span: 172800000000,
- start: function(d) {
- return new Date(d.getFullYear() - d.getFullYear() % 10, 0, 1);
- },
- fmt: function(d) {
- return "" + (d.getFullYear());
- },
- incr: function(d) {
- return d.setFullYear(d.getFullYear() + 10);
- }
- },
- "year": {
- span: 17280000000,
- start: function(d) {
- return new Date(d.getFullYear(), 0, 1);
- },
- fmt: function(d) {
- return "" + (d.getFullYear());
- },
- incr: function(d) {
- return d.setFullYear(d.getFullYear() + 1);
- }
- },
- "month": {
- span: 2419200000,
- start: function(d) {
- return new Date(d.getFullYear(), d.getMonth(), 1);
- },
- fmt: function(d) {
- return "" + (d.getFullYear()) + "-" + (Morris.pad2(d.getMonth() + 1));
- },
- incr: function(d) {
- return d.setMonth(d.getMonth() + 1);
- }
- },
- "day": {
- span: 86400000,
- start: function(d) {
- return new Date(d.getFullYear(), d.getMonth(), d.getDate());
- },
- fmt: function(d) {
- return "" + (d.getFullYear()) + "-" + (Morris.pad2(d.getMonth() + 1)) + "-" + (Morris.pad2(d.getDate()));
- },
- incr: function(d) {
- return d.setDate(d.getDate() + 1);
- }
- },
- "hour": minutesSpecHelper(60),
- "30min": minutesSpecHelper(30),
- "15min": minutesSpecHelper(15),
- "10min": minutesSpecHelper(10),
- "5min": minutesSpecHelper(5),
- "minute": minutesSpecHelper(1),
- "30sec": secondsSpecHelper(30),
- "15sec": secondsSpecHelper(15),
- "10sec": secondsSpecHelper(10),
- "5sec": secondsSpecHelper(5),
- "second": secondsSpecHelper(1)
- };
-
- Morris.AUTO_LABEL_ORDER = ["decade", "year", "month", "day", "hour", "30min", "15min", "10min", "5min", "minute", "30sec", "15sec", "10sec", "5sec", "second"];
-
Morris.Area = (function(_super) {
__extends(Area, _super);
@@ -1004,7 +1154,7 @@
Area.prototype.fillForSeries = function(i) {
var color;
- color = Raphael.rgb2hsl(this.colorForSeries(i));
+ color = Raphael.rgb2hsl(this.colorFor(this.data[i], i, 'line'));
return Raphael.hsl(color.h, Math.min(255, color.s * 0.75), Math.min(255, color.l * 1.25));
};
@@ -1016,12 +1166,15 @@
__extends(Bar, _super);
+ Bar.include(Morris.Hover);
+
+ Bar.prototype.hoverGetPosition = function(index) {
+ var x, y, _ref;
+ _ref = Morris.Hover.hoverGetPosition.call(this, index), x = _ref[0], y = _ref[1];
+ return [x, (this.top + this.bottom) / 2 - this.hoverHeight / 2];
+ };
+
function Bar(options) {
- this.updateHilight = __bind(this.updateHilight, this);
-
- this.hilight = __bind(this.hilight, this);
-
- this.updateHover = __bind(this.updateHover, this);
if (!(this instanceof Morris.Bar)) {
return new Morris.Bar(options);
}
@@ -1031,47 +1184,22 @@
}
Bar.prototype.init = function() {
- var touchHandler,
- _this = this;
- this.prevHilight = null;
- this.el.mousemove(function(evt) {
- return _this.updateHilight(evt.pageX);
- });
- if (this.options.hideHover) {
- this.el.mouseout(function(evt) {
- return _this.hilight(null);
- });
- }
- touchHandler = function(evt) {
- var touch;
- touch = evt.originalEvent.touches[0] || evt.originalEvent.changedTouches[0];
- _this.updateHilight(touch.pageX);
- return touch;
- };
- this.el.bind('touchstart', touchHandler);
- this.el.bind('touchmove', touchHandler);
- return this.el.bind('touchend', touchHandler);
+ return this.hoverConfigure(this.options.hoverOptions);
+ };
+
+ Bar.prototype.postInit = function() {
+ return this.hoverInit();
};
Bar.prototype.defaults = {
barSizeRatio: 0.75,
barGap: 3,
- barColors: ['#0b62a4', '#7a92a3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'],
- hoverPaddingX: 10,
- hoverPaddingY: 5,
- hoverMargin: 10,
- hoverFillColor: '#fff',
- hoverBorderColor: '#ccc',
- hoverBorderWidth: 2,
- hoverOpacity: 0.95,
- hoverLabelColor: '#444',
- hoverFontSize: 12,
- hideHover: false
+ barColors: ['#0b62a4', '#7a92a3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed']
};
Bar.prototype.calc = function() {
this.calcBars();
- return this.calcHoverMargins();
+ return this.hoverCalculateMargins();
};
Bar.prototype.calcBars = function() {
@@ -1099,23 +1227,9 @@
return _results;
};
- Bar.prototype.calcHoverMargins = function() {
- var i;
- return this.hoverMargins = (function() {
- var _i, _ref, _results;
- _results = [];
- for (i = _i = 1, _ref = this.data.length; 1 <= _ref ? _i < _ref : _i > _ref; i = 1 <= _ref ? ++_i : --_i) {
- _results.push(this.left + i * this.width / this.data.length);
- }
- return _results;
- }).call(this);
- };
-
Bar.prototype.draw = function() {
this.drawXAxis();
- this.drawSeries();
- this.drawHover();
- return this.hilight(this.options.hideHover ? null : this.data.length - 1);
+ return this.drawSeries();
};
Bar.prototype.drawXAxis = function() {
@@ -1177,79 +1291,6 @@
}).call(this);
};
- Bar.prototype.drawHover = function() {
- var i, yLabel, _i, _ref, _results;
- this.hoverHeight = this.options.hoverFontSize * 1.5 * (this.options.ykeys.length + 1);
- this.hover = this.r.rect(-10, -this.hoverHeight / 2 - this.options.hoverPaddingY, 20, this.hoverHeight + this.options.hoverPaddingY * 2, 10).attr('fill', this.options.hoverFillColor).attr('stroke', this.options.hoverBorderColor).attr('stroke-width', this.options.hoverBorderWidth).attr('opacity', this.options.hoverOpacity);
- this.xLabel = this.r.text(0, (this.options.hoverFontSize * 0.75) - this.hoverHeight / 2, '').attr('fill', this.options.hoverLabelColor).attr('font-weight', 'bold').attr('font-size', this.options.hoverFontSize);
- this.hoverSet = this.r.set();
- this.hoverSet.push(this.hover);
- this.hoverSet.push(this.xLabel);
- this.yLabels = [];
- _results = [];
- for (i = _i = 0, _ref = this.options.ykeys.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
- yLabel = this.r.text(0, this.options.hoverFontSize * 1.5 * (i + 1.5) - this.hoverHeight / 2, '').attr('font-size', this.options.hoverFontSize);
- this.yLabels.push(yLabel);
- _results.push(this.hoverSet.push(yLabel));
- }
- return _results;
- };
-
- Bar.prototype.updateHover = function(index) {
- var i, l, maxLabelWidth, row, xloc, y, yloc, _i, _len, _ref;
- this.hoverSet.show();
- row = this.data[index];
- this.xLabel.attr('text', row.label);
- _ref = row.y;
- for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
- y = _ref[i];
- this.yLabels[i].attr('fill', this.colorFor(row, i, 'hover'));
- this.yLabels[i].attr('text', "" + this.options.labels[i] + ": " + (this.yLabelFormat(y)));
- }
- maxLabelWidth = Math.max.apply(null, (function() {
- var _j, _len1, _ref1, _results;
- _ref1 = this.yLabels;
- _results = [];
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
- l = _ref1[_j];
- _results.push(l.getBBox().width);
- }
- return _results;
- }).call(this));
- maxLabelWidth = Math.max(maxLabelWidth, this.xLabel.getBBox().width);
- this.hover.attr('width', maxLabelWidth + this.options.hoverPaddingX * 2);
- this.hover.attr('x', -this.options.hoverPaddingX - maxLabelWidth / 2);
- yloc = (this.bottom + this.top) / 2;
- xloc = Math.min(this.right - maxLabelWidth / 2 - this.options.hoverPaddingX, this.data[index]._x);
- xloc = Math.max(this.left + maxLabelWidth / 2 + this.options.hoverPaddingX, xloc);
- return this.hoverSet.attr('transform', "t" + xloc + "," + yloc);
- };
-
- Bar.prototype.hideHover = function() {
- return this.hoverSet.hide();
- };
-
- Bar.prototype.hilight = function(index) {
- if (index !== null && this.prevHilight !== index) {
- this.updateHover(index);
- }
- this.prevHilight = index;
- if (!(index != null)) {
- return this.hideHover();
- }
- };
-
- Bar.prototype.updateHilight = function(x) {
- var hoverIndex, _i, _ref;
- x -= this.el.offset().left;
- for (hoverIndex = _i = 0, _ref = this.hoverMargins.length; 0 <= _ref ? _i < _ref : _i > _ref; hoverIndex = 0 <= _ref ? ++_i : --_i) {
- if (this.hoverMargins[hoverIndex] > x) {
- break;
- }
- }
- return this.hilight(hoverIndex);
- };
-
Bar.prototype.colorFor = function(row, sidx, type) {
var r, s;
if (typeof this.options.barColors === 'function') {
diff --git a/morris.min.js b/morris.min.js
index 2c8a0d1..d66583e 100644
--- a/morris.min.js
+++ b/morris.min.js
@@ -1 +1 @@
-(function(){var e,t,n,r,i=[].slice,s={}.hasOwnProperty,o=function(e,t){function r(){this.constructor=e}for(var n in t)s.call(t,n)&&(e[n]=t[n]);return r.prototype=t.prototype,e.prototype=new r,e.__super__=t.prototype,e},u=function(e,t){return function(){return e.apply(t,arguments)}},a=[].indexOf||function(e){for(var t=0,n=this.length;tn.length&&(r+=i.slice(n.length)),r):"-"},t.pad2=function(e){return(e<10?"0":"")+e},t.Grid=function(n){function r(t){typeof t.element=="string"?this.el=e(document.getElementById(t.element)):this.el=e(t.element);if(this.el==null||this.el.length===0)throw new Error("Graph container element not found");this.options=e.extend({},this.gridDefaults,this.defaults||{},t);if(this.options.data===void 0||this.options.data.length===0)return;typeof this.options.units=="string"&&(this.options.postUnits=t.units),this.r=new Raphael(this.el[0]),this.elementWidth=null,this.elementHeight=null,this.dirty=!1,this.init&&this.init(),this.setData(this.options.data)}return o(r,n),r.prototype.gridDefaults={dateFormat:null,gridLineColor:"#aaa",gridStrokeWidth:.5,gridTextColor:"#888",gridTextSize:12,numLines:5,padding:25,parseTime:!0,postUnits:"",preUnits:"",ymax:"auto",ymin:"auto 0",goals:[],goalStrokeWidth:1,goalLineColors:["#666633","#999966","#cc6666","#663333"],events:[],eventStrokeWidth:1,eventLineColors:["#005a04","#ccffbb","#3a5f0b","#005502"]},r.prototype.setData=function(e,n){var r,i,s,o,u,a,f,l,c,h,p,d;n==null&&(n=!0),h=this.cumulative?0:null,p=this.cumulative?0:null,this.options.goals.length>0&&(u=Math.min.apply(null,this.options.goals),o=Math.max.apply(null,this.options.goals),p=p!=null?Math.min(p,u):u,h=h!=null?Math.max(h,o):o),this.data=function(){var n,r,o;o=[];for(s=n=0,r=e.length;nt.x)-(t.x>e.x)})),this.xmin=this.data[0].x,this.xmax=this.data[this.data.length-1].x,this.events=[],this.options.parseTime&&this.options.events.length>0&&(this.events=function(){var e,n,i,s;i=this.options.events,s=[];for(e=0,n=i.length;e5?(this.ymax=parseInt(this.options.ymax.slice(5),10),h!=null&&(this.ymax=Math.max(h,this.ymax))):this.ymax=h!=null?h:0:this.ymax=parseInt(this.options.ymax,10):this.ymax=this.options.ymax,typeof this.options.ymin=="string"?this.options.ymin.slice(0,4)==="auto"?this.options.ymin.length>5?(this.ymin=parseInt(this.options.ymin.slice(5),10),p!=null&&(this.ymin=Math.min(p,this.ymin))):this.ymin=p!==null?p:0:this.ymin=parseInt(this.options.ymin,10):this.ymin=this.options.ymin,this.ymin===this.ymax&&(p&&(this.ymin-=1),this.ymax+=1),this.yInterval=(this.ymax-this.ymin)/(this.options.numLines-1),this.yInterval>0&&this.yInterval<1?this.precision=-Math.floor(Math.log(this.yInterval)/Math.log(10)):this.precision=0,this.dirty=!0;if(n)return this.redraw()},r.prototype._calc=function(){var e,t,n;n=this.el.width(),e=this.el.height();if(this.elementWidth!==n||this.elementHeight!==e||this.dirty){this.elementWidth=n,this.elementHeight=e,this.dirty=!1,t=Math.max(this.measureText(this.yAxisFormat(this.ymin),this.options.gridTextSize).width,this.measureText(this.yAxisFormat(this.ymax),this.options.gridTextSize).width),this.left=t+this.options.padding,this.right=this.elementWidth-this.options.padding,this.top=this.options.padding,this.bottom=this.elementHeight-this.options.padding-1.5*this.options.gridTextSize,this.width=this.right-this.left,this.height=this.bottom-this.top,this.dx=this.width/(this.xmax-this.xmin),this.dy=this.height/(this.ymax-this.ymin);if(this.calc)return this.calc()}},r.prototype.transY=function(e){return this.bottom-(e-this.ymin)*this.dy},r.prototype.transX=function(e){return this.data.length===1?(this.left+this.right)/2:this.left+(e-this.xmin)*this.dx},r.prototype.redraw=function(){this.r.clear(),this._calc(),this.drawGrid(),this.drawGoals(),this.drawEvents();if(this.draw)return this.draw()},r.prototype.drawGoals=function(){var e,t,n,r,i,s;i=this.options.goals,s=[];for(t=n=0,r=i.length;n=t;n=s+=o)r=parseFloat(n.toFixed(this.precision)),i=this.transY(r),this.r.text(this.left-this.options.padding/2,i,this.yAxisFormat(r)).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor).attr("text-anchor","end"),u.push(this.r.path("M"+this.left+","+i+"H"+(this.left+this.width)).attr("stroke",this.options.gridLineColor).attr("stroke-width",this.options.gridStrokeWidth));return u},r.prototype.measureText=function(e,t){var n,r;return t==null&&(t=12),r=this.r.text(100,100,e).attr("font-size",t),n=r.getBBox(),r.remove(),n},r.prototype.yAxisFormat=function(e){return this.yLabelFormat(e)},r.prototype.yLabelFormat=function(e){return""+this.options.preUnits+t.commas(e)+this.options.postUnits},r}(t.EventEmitter),t.parseDate=function(e){var t,n,r,i,s,o,u,a,f,l,c;return typeof e=="number"?e:(n=e.match(/^(\d+) Q(\d)$/),i=e.match(/^(\d+)-(\d+)$/),s=e.match(/^(\d+)-(\d+)-(\d+)$/),u=e.match(/^(\d+) W(\d+)$/),a=e.match(/^(\d+)-(\d+)-(\d+)[ T](\d+):(\d+)(Z|([+-])(\d\d):?(\d\d))?$/),f=e.match(/^(\d+)-(\d+)-(\d+)[ T](\d+):(\d+):(\d+(\.\d+)?)(Z|([+-])(\d\d):?(\d\d))?$/),n?(new Date(parseInt(n[1],10),parseInt(n[2],10)*3-1,1)).getTime():i?(new Date(parseInt(i[1],10),parseInt(i[2],10)-1,1)).getTime():s?(new Date(parseInt(s[1],10),parseInt(s[2],10)-1,parseInt(s[3],10))).getTime():u?(l=new Date(parseInt(u[1],10),0,1),l.getDay()!==4&&l.setMonth(0,1+(4-l.getDay()+7)%7),l.getTime()+parseInt(u[2],10)*6048e5):a?a[6]?(o=0,a[6]!=="Z"&&(o=parseInt(a[8],10)*60+parseInt(a[9],10),a[7]==="+"&&(o=0-o)),Date.UTC(parseInt(a[1],10),parseInt(a[2],10)-1,parseInt(a[3],10),parseInt(a[4],10),parseInt(a[5],10)+o)):(new Date(parseInt(a[1],10),parseInt(a[2],10)-1,parseInt(a[3],10),parseInt(a[4],10),parseInt(a[5],10))).getTime():f?(c=parseFloat(f[6]),t=Math.floor(c),r=Math.round((c-t)*1e3),f[8]?(o=0,f[8]!=="Z"&&(o=parseInt(f[10],10)*60+parseInt(f[11],10),f[9]==="+"&&(o=0-o)),Date.UTC(parseInt(f[1],10),parseInt(f[2],10)-1,parseInt(f[3],10),parseInt(f[4],10),parseInt(f[5],10)+o,t,r)):(new Date(parseInt(f[1],10),parseInt(f[2],10)-1,parseInt(f[3],10),parseInt(f[4],10),parseInt(f[5],10),t,r)).getTime()):(new Date(parseInt(e,10),0,1)).getTime())},t.Line=function(e){function n(e){this.updateHilight=u(this.updateHilight,this),this.hilight=u(this.hilight,this),this.updateHover=u(this.updateHover,this);if(!(this instanceof t.Line))return new t.Line(e);n.__super__.constructor.call(this,e)}return o(n,e),n.prototype.init=function(){var e,t=this;return this.pointGrow=Raphael.animation({r:this.options.pointSize+3},25,"linear"),this.pointShrink=Raphael.animation({r:this.options.pointSize},25,"linear"),this.prevHilight=null,this.el.mousemove(function(e){return t.updateHilight(e.pageX)}),this.options.hideHover&&this.el.mouseout(function(e){return t.hilight(null)}),e=function(e){var n;return n=e.originalEvent.touches[0]||e.originalEvent.changedTouches[0],t.updateHilight(n.pageX),n},this.el.bind("touchstart",e),this.el.bind("touchmove",e),this.el.bind("touchend",e)},n.prototype.defaults={lineWidth:3,pointSize:4,lineColors:["#0b62a4","#7A92A3","#4da74d","#afd8f8","#edc240","#cb4b4b","#9440ed"],pointWidths:[1],pointStrokeColors:["#ffffff"],pointFillColors:[],hoverPaddingX:10,hoverPaddingY:5,hoverMargin:10,hoverFillColor:"#fff",hoverBorderColor:"#ccc",hoverBorderWidth:2,hoverOpacity:.95,hoverLabelColor:"#444",hoverFontSize:12,smooth:!0,hideHover:!1,xLabels:"auto",xLabelFormat:null},n.prototype.calc=function(){return this.calcPoints(),this.generatePaths(),this.calcHoverMargins()},n.prototype.calcPoints=function(){var e,t,n,r,i,s;i=this.data,s=[];for(n=0,r=i.length;ns;t=0<=s?++i:--i)r=this.options.smooth===!0||(o=this.options.ykeys[t],a.call(this.options.smooth,o)>=0),e=function(){var e,r,i,s;i=this.data,s=[];for(e=0,r=i.length;e1?u.push(this.createPath(e,r)):u.push(null);return u}.call(this)},n.prototype.draw=function(){return this.drawXAxis(),this.drawSeries(),this.drawHover(),this.hilight(this.options.hideHover?null:this.data.length-1)},n.prototype.drawXAxis=function(){var e,n,r,i,s,o,u,a,f,l,c=this;u=this.bottom+this.options.gridTextSize*1.25,o=50,i=null,e=function(e,t){var n,r;return n=c.r.text(c.transX(t),u,e).attr("font-size",c.options.gridTextSize).attr("fill",c.options.gridTextColor),r=n.getBBox(),(i==null||i>=r.x+r.width)&&r.x>=0&&r.x+r.width=0;t=o<=0?++i:--i)n=this.paths[t],n!==null&&this.r.path(n).attr("stroke",this.colorForSeries(t)).attr("stroke-width",this.options.lineWidth);this.seriesPoints=function(){var e,n,r;r=[];for(t=e=0,n=this.options.ykeys.length;0<=n?en;t=0<=n?++e:--e)r.push([]);return r}.call(this),a=[];for(t=s=u=this.options.ykeys.length-1;u<=0?s<=0:s>=0;t=u<=0?++s:--s)a.push(function(){var n,i,s,o;s=this.data,o=[];for(n=0,i=s.length;n=v;s=0<=v?++d:--d)n=e[s],s===0?f+="M"+n.x+","+n.y:(r=i[s],u=e[s-1],a=i[s-1],o=(n.x-u.x)/4,l=u.x+o,h=Math.min(this.bottom,u.y+o*a),c=n.x-o,p=Math.min(this.bottom,n.y-o*r),f+="C"+l+","+h+","+c+","+p+","+n.x+","+n.y)}else f="M"+function(){var t,r,i;i=[];for(t=0,r=e.length;ti;e=0<=i?++r:--r)t=this.cumulative?this.options.ykeys.length-e-1:e,n=this.r.text(0,this.options.hoverFontSize*1.5*(t+1.5)-this.hoverHeight/2,"").attr("fill",this.colorForSeries(e)).attr("font-size",this.options.hoverFontSize),this.yLabels.push(n),s.push(this.hoverSet.push(n));return s},n.prototype.updateHover=function(e){var t,n,r,i,s,o,u,a,f,l;this.hoverSet.show(),i=this.data[e],this.xLabel.attr("text",i.label),l=i.y;for(t=a=0,f=l.length;athis.hoverHeight+this.options.hoverPaddingY*2+this.options.hoverMargin+this.top?u=u-this.hoverHeight/2-this.options.hoverPaddingY-this.options.hoverMargin:u=u+this.hoverHeight/2+this.options.hoverPaddingY+this.options.hoverMargin,u=Math.max(this.top+this.hoverHeight/2+this.options.hoverPaddingY,u),u=Math.min(this.bottom-this.hoverHeight/2-this.options.hoverPaddingY,u),s=Math.min(this.right-r/2-this.options.hoverPaddingX,this.data[e]._x),s=Math.max(this.left+r/2+this.options.hoverPaddingX,s),this.hoverSet.attr("transform","t"+s+","+u)},n.prototype.hideHover=function(){return this.hoverSet.hide()},n.prototype.hilight=function(e){var t,n,r,i,s;if(this.prevHilight!==null&&this.prevHilight!==e)for(t=n=0,i=this.seriesPoints.length-1;0<=i?n<=i:n>=i;t=0<=i?++n:--n)this.seriesPoints[t][this.prevHilight]&&this.seriesPoints[t][this.prevHilight].animate(this.pointShrink);if(e!==null&&this.prevHilight!==e){for(t=r=0,s=this.seriesPoints.length-1;0<=s?r<=s:r>=s;t=0<=s?++r:--r)this.seriesPoints[t][e]&&this.seriesPoints[t][e].animate(this.pointGrow);this.updateHover(e)}this.prevHilight=e;if(e==null)return this.hideHover()},n.prototype.updateHilight=function(e){var t,n,r;e-=this.el.offset().left;for(t=n=0,r=this.hoverMargins.length;0<=r?nr;t=0<=r?++n:--n)if(this.hoverMargins[t]>e)break;return this.hilight(t)},n.prototype.colorForSeries=function(e){return this.options.lineColors[e%this.options.lineColors.length]},n.prototype.strokeWidthForSeries=function(e){return this.options.pointWidths[e%this.options.pointWidths.length]},n.prototype.strokeForSeries=function(e){return this.options.pointStrokeColors[e%this.options.pointStrokeColors.length]},n.prototype.pointFillColorForSeries=function(e){return this.options.pointFillColors[e%this.options.pointFillColors.length]},n}(t.Grid),t.labelSeries=function(n,r,i,s,o){var u,a,f,l,c,h,p,d,v,m,g;f=200*(r-n)/i,a=new Date(n),p=t.LABEL_SPECS[s];if(p===void 0){g=t.AUTO_LABEL_ORDER;for(v=0,m=g.length;v=h.span){p=h;break}}}p===void 0&&(p=t.LABEL_SPECS.second),o&&(p=e.extend({},p,{fmt:o})),u=p.start(a),c=[];while((d=u.getTime())<=r)d>=n&&c.push([p.fmt(u),d]),p.incr(u);return c},n=function(e){return{span:e*60*1e3,start:function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours())},fmt:function(e){return""+t.pad2(e.getHours())+":"+t.pad2(e.getMinutes())},incr:function(t){return t.setMinutes(t.getMinutes()+e)}}},r=function(e){return{span:e*1e3,start:function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes())},fmt:function(e){return""+t.pad2(e.getHours())+":"+t.pad2(e.getMinutes())+":"+t.pad2(e.getSeconds())},incr:function(t){return t.setSeconds(t.getSeconds()+e)}}},t.LABEL_SPECS={decade:{span:1728e8,start:function(e){return new Date(e.getFullYear()-e.getFullYear()%10,0,1)},fmt:function(e){return""+e.getFullYear()},incr:function(e){return e.setFullYear(e.getFullYear()+10)}},year:{span:1728e7,start:function(e){return new Date(e.getFullYear(),0,1)},fmt:function(e){return""+e.getFullYear()},incr:function(e){return e.setFullYear(e.getFullYear()+1)}},month:{span:24192e5,start:function(e){return new Date(e.getFullYear(),e.getMonth(),1)},fmt:function(e){return""+e.getFullYear()+"-"+t.pad2(e.getMonth()+1)},incr:function(e){return e.setMonth(e.getMonth()+1)}},day:{span:864e5,start:function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate())},fmt:function(e){return""+e.getFullYear()+"-"+t.pad2(e.getMonth()+1)+"-"+t.pad2(e.getDate())},incr:function(e){return e.setDate(e.getDate()+1)}},hour:n(60),"30min":n(30),"15min":n(15),"10min":n(10),"5min":n(5),minute:n(1),"30sec":r(30),"15sec":r(15),"10sec":r(10),"5sec":r(5),second:r(1)},t.AUTO_LABEL_ORDER=["decade","year","month","day","hour","30min","15min","10min","5min","minute","30sec","15sec","10sec","5sec","second"],t.Area=function(e){function n(e){if(!(this instanceof t.Area))return new t.Area(e);this.cumulative=!0,n.__super__.constructor.call(this,e)}return o(n,e),n.prototype.calcPoints=function(){var e,t,n,r,i,s,o;s=this.data,o=[];for(r=0,i=s.length;r=0;e=i<=0?++r:--r)t=this.paths[e],t!==null&&(t+="L"+this.transX(this.xmax)+","+this.bottom+"L"+this.transX(this.xmin)+","+this.bottom+"Z",this.r.path(t).attr("fill",this.fillForSeries(e)).attr("stroke-width",0));return n.__super__.drawSeries.call(this)},n.prototype.fillForSeries=function(e){var t;return t=Raphael.rgb2hsl(this.colorForSeries(e)),Raphael.hsl(t.h,Math.min(255,t.s*.75),Math.min(255,t.l*1.25))},n}(t.Line),t.Bar=function(n){function r(n){this.updateHilight=u(this.updateHilight,this),this.hilight=u(this.hilight,this),this.updateHover=u(this.updateHover,this);if(!(this instanceof t.Bar))return new t.Bar(n);r.__super__.constructor.call(this,e.extend({},n,{parseTime:!1}))}return o(r,n),r.prototype.init=function(){var e,t=this;return this.prevHilight=null,this.el.mousemove(function(e){return t.updateHilight(e.pageX)}),this.options.hideHover&&this.el.mouseout(function(e){return t.hilight(null)}),e=function(e){var n;return n=e.originalEvent.touches[0]||e.originalEvent.changedTouches[0],t.updateHilight(n.pageX),n},this.el.bind("touchstart",e),this.el.bind("touchmove",e),this.el.bind("touchend",e)},r.prototype.defaults={barSizeRatio:.75,barGap:3,barColors:["#0b62a4","#7a92a3","#4da74d","#afd8f8","#edc240","#cb4b4b","#9440ed"],hoverPaddingX:10,hoverPaddingY:5,hoverMargin:10,hoverFillColor:"#fff",hoverBorderColor:"#ccc",hoverBorderWidth:2,hoverOpacity:.95,hoverLabelColor:"#444",hoverFontSize:12,hideHover:!1},r.prototype.calc=function(){return this.calcBars(),this.calcHoverMargins()},r.prototype.calcBars=function(){var e,t,n,r,i,s,o;s=this.data,o=[];for(e=r=0,i=s.length;rn;e=1<=n?++t:--t)r.push(this.left+e*this.width/this.data.length);return r}.call(this)},r.prototype.draw=function(){return this.drawXAxis(),this.drawSeries(),this.drawHover(),this.hilight(this.options.hideHover?null:this.data.length-1)},r.prototype.drawXAxis=function(){var e,t,n,r,i,s,o,u,a,f;o=this.bottom+this.options.gridTextSize*1.25,s=50,r=null,f=[];for(e=u=0,a=this.data.length;0<=a?ua;e=0<=a?++u:--u)i=this.data[this.data.length-1-e],t=this.r.text(i._x,o,i.label).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor),n=t.getBBox(),(r==null||r>=n.x+n.width)&&n.x>=0&&n.x+n.width=0?this.transY(0):null,this.bars=function(){var o,h,p,d;p=this.data,d=[];for(r=o=0,h=p.length;or;e=0<=r?++n:--n)t=this.r.text(0,this.options.hoverFontSize*1.5*(e+1.5)-this.hoverHeight/2,"").attr("font-size",this.options.hoverFontSize),this.yLabels.push(t),i.push(this.hoverSet.push(t));return i},r.prototype.updateHover=function(e){var t,n,r,i,s,o,u,a,f,l;this.hoverSet.show(),i=this.data[e],this.xLabel.attr("text",i.label),l=i.y;for(t=a=0,f=l.length;ar;t=0<=r?++n:--n)if(this.hoverMargins[t]>e)break;return this.hilight(t)},r.prototype.colorFor=function(e,t,n){var r,i;return typeof this.options.barColors=="function"?(r={x:e.x,y:e.y[t],label:e.label},i={index:t,key:this.options.ykeys[t],label:this.options.labels[t]},this.options.barColors.call(this,r,i,n)):this.options.barColors[t%this.options.barColors.length]},r}(t.Grid),t.Donut=function(){function n(n){this.select=u(this.select,this);if(!(this instanceof t.Donut))return new t.Donut(n);typeof n.element=="string"?this.el=e(document.getElementById(n.element)):this.el=e(n.element),this.options=e.extend({},this.defaults,n);if(this.el===null||this.el.length===0)throw new Error("Graph placeholder not found.");if(n.data===void 0||n.data.length===0)return;this.data=n.data,this.redraw()}return n.prototype.defaults={colors:["#0B62A4","#3980B5","#679DC6","#95BBD7","#B0CCE1","#095791","#095085","#083E67","#052C48","#042135"],formatter:t.commas},n.prototype.redraw=function(){var e,n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y,b,w,E,S,x;this.el.empty(),this.r=new Raphael(this.el[0]),n=this.el.width()/2,r=this.el.height()/2,h=(Math.min(n,r)-10)/3,c=0,w=this.data;for(d=0,g=w.length;dMath.PI?1:0,this.path=this.calcSegment(this.inner+3,this.inner+this.outer-5),this.selectedPath=this.calcSegment(this.inner+3,this.inner+this.outer),this.hilight=this.calcArc(this.inner)}return o(t,e),t.prototype.calcArcPoints=function(e){return[this.cx+e*this.sin_p0,this.cy+e*this.cos_p0,this.cx+e*this.sin_p1,this.cy+e*this.cos_p1]},t.prototype.calcSegment=function(e,t){var n,r,i,s,o,u,a,f,l,c;return l=this.calcArcPoints(e),n=l[0],i=l[1],r=l[2],s=l[3],c=this.calcArcPoints(t),o=c[0],a=c[1],u=c[2],f=c[3],"M"+n+","+i+("A"+e+","+e+",0,"+this.long+",0,"+r+","+s)+("L"+u+","+f)+("A"+t+","+t+",0,"+this.long+",1,"+o+","+a)+"Z"},t.prototype.calcArc=function(e){var t,n,r,i,s;return s=this.calcArcPoints(e),t=s[0],r=s[1],n=s[2],i=s[3],"M"+t+","+r+("A"+e+","+e+",0,"+this.long+",0,"+n+","+i)},t.prototype.render=function(e){var t=this;return this.arc=e.path(this.hilight).attr({stroke:this.color,"stroke-width":2,opacity:0}),this.seg=e.path(this.path).attr({fill:this.color,stroke:"white","stroke-width":3}).hover(function(){return t.fire("hover",t)})},t.prototype.select=function(){if(!this.selected)return this.seg.animate({path:this.selectedPath},150,"<>"),this.arc.animate({opacity:1},150,"<>"),this.selected=!0},t.prototype.deselect=function(){if(this.selected)return this.seg.animate({path:this.path},150,"<>"),this.arc.animate({opacity:0},150,"<>"),this.selected=!1},t}(t.EventEmitter)}).call(this);
\ No newline at end of file
+(function(){var e,t,n,r,i={}.hasOwnProperty,s=function(e,t){function r(){this.constructor=e}for(var n in t)i.call(t,n)&&(e[n]=t[n]);return r.prototype=t.prototype,e.prototype=new r,e.__super__=t.prototype,e},o=[].slice,u=function(e,t){return function(){return e.apply(t,arguments)}},a=[].indexOf||function(e){for(var t=0,n=this.length;tn.length&&(r+=i.slice(n.length)),r):"-"},t.pad2=function(e){return(e<10?"0":"")+e},t.labelSeries=function(n,r,i,s,o){var u,a,f,l,c,h,p,d,v,m,g;f=200*(r-n)/i,a=new Date(n),p=t.LABEL_SPECS[s];if(p===void 0){g=t.AUTO_LABEL_ORDER;for(v=0,m=g.length;v=h.span){p=h;break}}}p===void 0&&(p=t.LABEL_SPECS.second),o&&(p=e.extend({},p,{fmt:o})),u=p.start(a),c=[];while((d=u.getTime())<=r)d>=n&&c.push([p.fmt(u),d]),p.incr(u);return c},n=function(e){return{span:e*60*1e3,start:function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours())},fmt:function(e){return""+t.pad2(e.getHours())+":"+t.pad2(e.getMinutes())},incr:function(t){return t.setMinutes(t.getMinutes()+e)}}},r=function(e){return{span:e*1e3,start:function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes())},fmt:function(e){return""+t.pad2(e.getHours())+":"+t.pad2(e.getMinutes())+":"+t.pad2(e.getSeconds())},incr:function(t){return t.setSeconds(t.getSeconds()+e)}}},t.LABEL_SPECS={decade:{span:1728e8,start:function(e){return new Date(e.getFullYear()-e.getFullYear()%10,0,1)},fmt:function(e){return""+e.getFullYear()},incr:function(e){return e.setFullYear(e.getFullYear()+10)}},year:{span:1728e7,start:function(e){return new Date(e.getFullYear(),0,1)},fmt:function(e){return""+e.getFullYear()},incr:function(e){return e.setFullYear(e.getFullYear()+1)}},month:{span:24192e5,start:function(e){return new Date(e.getFullYear(),e.getMonth(),1)},fmt:function(e){return""+e.getFullYear()+"-"+t.pad2(e.getMonth()+1)},incr:function(e){return e.setMonth(e.getMonth()+1)}},day:{span:864e5,start:function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate())},fmt:function(e){return""+e.getFullYear()+"-"+t.pad2(e.getMonth()+1)+"-"+t.pad2(e.getDate())},incr:function(e){return e.setDate(e.getDate()+1)}},hour:n(60),"30min":n(30),"15min":n(15),"10min":n(10),"5min":n(5),minute:n(1),"30sec":r(30),"15sec":r(15),"10sec":r(10),"5sec":r(5),second:r(1)},t.AUTO_LABEL_ORDER=["decade","year","month","day","hour","30min","15min","10min","5min","minute","30sec","15sec","10sec","5sec","second"],t.Grid=function(n){function r(t){typeof t.element=="string"?this.el=e(document.getElementById(t.element)):this.el=e(t.element);if(this.el==null||this.el.length===0)throw new Error("Graph container element not found");this.options=e.extend({},this.gridDefaults,this.defaults||{},t);if(this.options.data===void 0||this.options.data.length===0)return;typeof this.options.units=="string"&&(this.options.postUnits=t.units),this.r=new Raphael(this.el[0]),this.elementWidth=null,this.elementHeight=null,this.dirty=!1,this.init&&this.init(),this.setData(this.options.data),this.postInit&&this.postInit()}return s(r,n),r.prototype.gridDefaults={dateFormat:null,gridLineColor:"#aaa",gridStrokeWidth:.5,gridTextColor:"#888",gridTextSize:12,numLines:5,padding:25,parseTime:!0,postUnits:"",preUnits:"",ymax:"auto",ymin:"auto 0",goals:[],goalStrokeWidth:1,goalLineColors:["#666633","#999966","#cc6666","#663333"],events:[],eventStrokeWidth:1,eventLineColors:["#005a04","#ccffbb","#3a5f0b","#005502"]},r.prototype.setData=function(e,n){var r,i,s,o,u,a,f,l,c,h,p,d;n==null&&(n=!0),h=this.cumulative?0:null,p=this.cumulative?0:null,this.options.goals.length>0&&(u=Math.min.apply(null,this.options.goals),o=Math.max.apply(null,this.options.goals),p=p!=null?Math.min(p,u):u,h=h!=null?Math.max(h,o):o),this.data=function(){var n,r,o;o=[];for(s=n=0,r=e.length;nt.x)-(t.x>e.x)})),this.xmin=this.data[0].x,this.xmax=this.data[this.data.length-1].x,this.events=[],this.options.parseTime&&this.options.events.length>0&&(this.events=function(){var e,n,i,s;i=this.options.events,s=[];for(e=0,n=i.length;e5?(this.ymax=parseInt(this.options.ymax.slice(5),10),h!=null&&(this.ymax=Math.max(h,this.ymax))):this.ymax=h!=null?h:0:this.ymax=parseInt(this.options.ymax,10):this.ymax=this.options.ymax,typeof this.options.ymin=="string"?this.options.ymin.slice(0,4)==="auto"?this.options.ymin.length>5?(this.ymin=parseInt(this.options.ymin.slice(5),10),p!=null&&(this.ymin=Math.min(p,this.ymin))):this.ymin=p!==null?p:0:this.ymin=parseInt(this.options.ymin,10):this.ymin=this.options.ymin,this.ymin===this.ymax&&(p&&(this.ymin-=1),this.ymax+=1),this.yInterval=(this.ymax-this.ymin)/(this.options.numLines-1),this.yInterval>0&&this.yInterval<1?this.precision=-Math.floor(Math.log(this.yInterval)/Math.log(10)):this.precision=0,this.dirty=!0;if(n)return this.redraw()},r.prototype._calc=function(){var e,t,n;n=this.el.width(),e=this.el.height();if(this.elementWidth!==n||this.elementHeight!==e||this.dirty){this.elementWidth=n,this.elementHeight=e,this.dirty=!1,t=Math.max(this.measureText(this.yAxisFormat(this.ymin),this.options.gridTextSize).width,this.measureText(this.yAxisFormat(this.ymax),this.options.gridTextSize).width),this.left=t+this.options.padding,this.right=this.elementWidth-this.options.padding,this.top=this.options.padding,this.bottom=this.elementHeight-this.options.padding-1.5*this.options.gridTextSize,this.width=this.right-this.left,this.height=this.bottom-this.top,this.dx=this.width/(this.xmax-this.xmin),this.dy=this.height/(this.ymax-this.ymin);if(this.calc)return this.calc()}},r.prototype.transY=function(e){return this.bottom-(e-this.ymin)*this.dy},r.prototype.transX=function(e){return this.data.length===1?(this.left+this.right)/2:this.left+(e-this.xmin)*this.dx},r.prototype.redraw=function(){this.r.clear(),this._calc(),this.drawGrid(),this.drawGoals(),this.drawEvents();if(this.draw)return this.draw()},r.prototype.drawGoals=function(){var e,t,n,r,i,s;i=this.options.goals,s=[];for(t=n=0,r=i.length;n=t;n=s+=o)r=parseFloat(n.toFixed(this.precision)),i=this.transY(r),this.r.text(this.left-this.options.padding/2,i,this.yAxisFormat(r)).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor).attr("text-anchor","end"),u.push(this.r.path("M"+this.left+","+i+"H"+(this.left+this.width)).attr("stroke",this.options.gridLineColor).attr("stroke-width",this.options.gridStrokeWidth));return u},r.prototype.measureText=function(e,t){var n,r;return t==null&&(t=12),r=this.r.text(100,100,e).attr("font-size",t),n=r.getBBox(),r.remove(),n},r.prototype.yAxisFormat=function(e){return this.yLabelFormat(e)},r.prototype.yLabelFormat=function(e){return""+this.options.preUnits+t.commas(e)+this.options.postUnits},r}(t.EventEmitter),t.parseDate=function(e){var t,n,r,i,s,o,u,a,f,l,c;return typeof e=="number"?e:(n=e.match(/^(\d+) Q(\d)$/),i=e.match(/^(\d+)-(\d+)$/),s=e.match(/^(\d+)-(\d+)-(\d+)$/),u=e.match(/^(\d+) W(\d+)$/),a=e.match(/^(\d+)-(\d+)-(\d+)[ T](\d+):(\d+)(Z|([+-])(\d\d):?(\d\d))?$/),f=e.match(/^(\d+)-(\d+)-(\d+)[ T](\d+):(\d+):(\d+(\.\d+)?)(Z|([+-])(\d\d):?(\d\d))?$/),n?(new Date(parseInt(n[1],10),parseInt(n[2],10)*3-1,1)).getTime():i?(new Date(parseInt(i[1],10),parseInt(i[2],10)-1,1)).getTime():s?(new Date(parseInt(s[1],10),parseInt(s[2],10)-1,parseInt(s[3],10))).getTime():u?(l=new Date(parseInt(u[1],10),0,1),l.getDay()!==4&&l.setMonth(0,1+(4-l.getDay()+7)%7),l.getTime()+parseInt(u[2],10)*6048e5):a?a[6]?(o=0,a[6]!=="Z"&&(o=parseInt(a[8],10)*60+parseInt(a[9],10),a[7]==="+"&&(o=0-o)),Date.UTC(parseInt(a[1],10),parseInt(a[2],10)-1,parseInt(a[3],10),parseInt(a[4],10),parseInt(a[5],10)+o)):(new Date(parseInt(a[1],10),parseInt(a[2],10)-1,parseInt(a[3],10),parseInt(a[4],10),parseInt(a[5],10))).getTime():f?(c=parseFloat(f[6]),t=Math.floor(c),r=Math.round((c-t)*1e3),f[8]?(o=0,f[8]!=="Z"&&(o=parseInt(f[10],10)*60+parseInt(f[11],10),f[9]==="+"&&(o=0-o)),Date.UTC(parseInt(f[1],10),parseInt(f[2],10)-1,parseInt(f[3],10),parseInt(f[4],10),parseInt(f[5],10)+o,t,r)):(new Date(parseInt(f[1],10),parseInt(f[2],10)-1,parseInt(f[3],10),parseInt(f[4],10),parseInt(f[5],10),t,r)).getTime()):(new Date(parseInt(e,10),0,1)).getTime())},t.Hover={hoverConfigure:function(t){return this.hoverOptions=e.extend({},this.hoverDefaults,t!=null?t:{})},hoverInit:function(){if(this.hoverOptions.enableHover)return this.hover=this.hoverBuild(),this.hoverBindEvents(),this.hoverShow(this.hoverOptions.hideHover?null:this.data.length-1)},hoverDefaults:{enableHover:!0,popupClass:"morris-popup",hideHover:!1,allowOverflow:!1,pointMargin:10,hoverFill:function(e,t){return this.hoverFill(e,t)}},hoverBindEvents:function(){var e,t=this;return this.el.mousemove(function(e){return t.hoverUpdate(e.pageX)}),this.hoverOptions.hideHover&&this.el.mouseout(function(e){return t.hoverShow(null)}),e=function(e){var n;return n=e.originalEvent.touches[0]||e.originalEvent.changedTouches[0],t.hoverUpdate(n.pageX),n},this.el.bind("touchstart",e),this.el.bind("touchmove",e),this.el.bind("touchend",e),this.hover.mousemove(function(e){return e.stopPropagation()}),this.hover.mouseout(function(e){return e.stopPropagation()}),this.hover.bind("touchstart",function(e){return e.stopPropagation()}),this.hover.bind("touchmove",function(e){return e.stopPropagation()}),this.hover.bind("touchend",function(e){return e.stopPropagation()})},hoverCalculateMargins:function(){var e;return this.hoverMargins=function(){var t,n,r;r=[];for(e=t=1,n=this.data.length;1<=n?tn;e=1<=n?++t:--t)r.push(this.left+e*this.width/this.data.length);return r}.call(this)},hoverBuild:function(){var t;return t=e(""),t.addClass(""+this.hoverOptions.popupClass+" js-morris-popup"),t.appendTo(this.el),t.hide(),t},hoverUpdate:function(e){var t,n,r;e-=this.el.offset().left;for(t=n=0,r=this.hoverMargins.length;0<=r?nr;t=0<=r?++n:--n)if(this.hoverMargins[t]>e)break;return this.hoverShow(t)},hoverShow:function(e){e!==null&&(this.hover.html(""),this.hoverOptions.hoverFill.call(this,e,this.data[e]),this.hoverPosition(e),this.fire("hover.show",e),this.hover.show());if(e==null)return this.hoverHide()},hoverHide:function(){return this.hover.hide()},colorFor:function(e,t,n){return"inherit"},yLabelFormat:function(e){return t.commas(e)},hoverPosition:function(e){var t,n,r;return r=this.hoverGetPosition(e),t=r[0],n=r[1],this.hover.css({top:""+(this.el.offset().top+n)+"px",left:""+(this.el.offset().left+t)+"px"})},hoverGetPosition:function(e){var t,n,r,i;return n=this.data[e],this.hoverWidth=this.hover.outerWidth(!0),this.hoverHeight=this.hover.outerHeight(!0),t=i=Math.min.apply(null,function(){var e,t,r,s;r=n._y,s=[];for(e=0,t=r.length;ethis.right-this.hoverWidth&&(r=n._x-this.hoverWidth-this.hoverOptions.pointMargin),i=Math.max(i,this.top),i=Math.min(i,this.bottom-this.hoverHeight-this.hoverOptions.pointMargin),i-t"),i.text(n.label),i.appendTo(this.hover),f=n.y,l=[];for(r=u=0,a=f.length;u"),o.css("color",this.colorFor(n,r,"hover")),o.text(""+this.options.labels[r]+": "+this.yLabelFormat(s)),l.push(o.appendTo(this.hover));return l}},t.Line=function(e){function n(e){this.updateHilight=u(this.updateHilight,this),this.hilight=u(this.hilight,this);if(!(this instanceof t.Line))return new t.Line(e);n.__super__.constructor.call(this,e)}return s(n,e),n.include(t.Hover),n.prototype.init=function(){var e,t=this;this.pointGrow=Raphael.animation({r:this.options.pointSize+3},25,"linear"),this.pointShrink=Raphael.animation({r:this.options.pointSize},25,"linear"),this.hoverConfigure(this.options.hoverOptions);if(this.options.hilight)return this.prevHilight=null,this.el.mousemove(function(e){return t.updateHilight(e.pageX)}),this.options.hilightAutoHide&&this.el.mouseout(function(e){return t.hilight(null)}),e=function(e){var n;return n=e.originalEvent.touches[0]||e.originalEvent.changedTouches[0],t.updateHilight(n.pageX),n},this.el.bind("touchstart",e),this.el.bind("touchmove",e),this.el.bind("touchend",e)},n.prototype.postInit=function(){return this.hoverInit()},n.prototype.defaults={lineWidth:3,pointSize:4,lineColors:["#0b62a4","#7A92A3","#4da74d","#afd8f8","#edc240","#cb4b4b","#9440ed"],pointWidths:[1],pointStrokeColors:["#ffffff"],pointFillColors:[],smooth:!0,hilight:!0,hilightAutoHide:!1,xLabels:"auto",xLabelFormat:null},n.prototype.calc=function(){return this.calcPoints(),this.hoverCalculateMargins(),this.generatePaths(),this.calcHilightMargins()},n.prototype.calcPoints=function(){var e,t,n,r,i,s;i=this.data,s=[];for(n=0,r=i.length;ns;t=0<=s?++i:--i)r=this.options.smooth===!0||(o=this.options.ykeys[t],a.call(this.options.smooth,o)>=0),e=function(){var e,r,i,s;i=this.data,s=[];for(e=0,r=i.length;e1?u.push(this.createPath(e,r)):u.push(null);return u}.call(this)},n.prototype.draw=function(){this.drawXAxis(),this.drawSeries();if(this.options.hilight)return this.hilight(this.options.hilightAutoHide?null:this.data.length-1)},n.prototype.drawXAxis=function(){var e,n,r,i,s,o,u,a,f,l,c=this;u=this.bottom+this.options.gridTextSize*1.25,o=50,i=null,e=function(e,t){var n,r;return n=c.r.text(c.transX(t),u,e).attr("font-size",c.options.gridTextSize).attr("fill",c.options.gridTextColor),r=n.getBBox(),(i==null||i>=r.x+r.width)&&r.x>=0&&r.x+r.width=0;t=o<=0?++i:--i)n=this.paths[t],n!==null&&this.r.path(n).attr("stroke",this.colorFor(r,t,"line")).attr("stroke-width",this.options.lineWidth);this.seriesPoints=function(){var e,n,r;r=[];for(t=e=0,n=this.options.ykeys.length;0<=n?en;t=0<=n?++e:--e)r.push([]);return r}.call(this),a=[];for(t=s=u=this.options.ykeys.length-1;u<=0?s<=0:s>=0;t=u<=0?++s:--s)a.push(function(){var n,i,s,o;s=this.data,o=[];for(n=0,i=s.length;n=v;s=0<=v?++d:--d)n=e[s],s===0?f+="M"+n.x+","+n.y:(r=i[s],u=e[s-1],a=i[s-1],o=(n.x-u.x)/4,l=u.x+o,h=Math.min(this.bottom,u.y+o*a),c=n.x-o,p=Math.min(this.bottom,n.y-o*r),f+="C"+l+","+h+","+c+","+p+","+n.x+","+n.y)}else f="M"+function(){var t,r,i;i=[];for(t=0,r=e.length;t=i;t=0<=i?++n:--n)this.seriesPoints[t][this.prevHilight]&&this.seriesPoints[t][this.prevHilight].animate(this.pointShrink);if(e!==null&&this.prevHilight!==e)for(t=r=0,s=this.seriesPoints.length-1;0<=s?r<=s:r>=s;t=0<=s?++r:--r)this.seriesPoints[t][e]&&this.seriesPoints[t][e].animate(this.pointGrow);return this.prevHilight=e},n.prototype.updateHilight=function(e){var t,n,r;e-=this.el.offset().left;for(t=n=0,r=this.hilightMargins.length;0<=r?nr;t=0<=r?++n:--n)if(this.hilightMargins[t]>e)break;return this.hilight(t)},n.prototype.strokeWidthForSeries=function(e){return this.options.pointWidths[e%this.options.pointWidths.length]},n.prototype.strokeForSeries=function(e){return this.options.pointStrokeColors[e%this.options.pointStrokeColors.length]},n.prototype.colorFor=function(e,t,n){return typeof this.options.lineColors=="function"?this.options.lineColors.call(this,e,t,n):n==="point"?this.options.pointFillColors[t%this.options.pointFillColors.length]||this.options.lineColors[t%this.options.lineColors.length]:this.options.lineColors[t%this.options.lineColors.length]},n}(t.Grid),t.Area=function(e){function n(e){if(!(this instanceof t.Area))return new t.Area(e);this.cumulative=!0,n.__super__.constructor.call(this,e)}return s(n,e),n.prototype.calcPoints=function(){var e,t,n,r,i,s,o;s=this.data,o=[];for(r=0,i=s.length;r=0;e=i<=0?++r:--r)t=this.paths[e],t!==null&&(t+="L"+this.transX(this.xmax)+","+this.bottom+"L"+this.transX(this.xmin)+","+this.bottom+"Z",this.r.path(t).attr("fill",this.fillForSeries(e)).attr("stroke-width",0));return n.__super__.drawSeries.call(this)},n.prototype.fillForSeries=function(e){var t;return t=Raphael.rgb2hsl(this.colorFor(this.data[e],e,"line")),Raphael.hsl(t.h,Math.min(255,t.s*.75),Math.min(255,t.l*1.25))},n}(t.Line),t.Bar=function(n){function r(n){if(!(this instanceof t.Bar))return new t.Bar(n);r.__super__.constructor.call(this,e.extend({},n,{parseTime:!1}))}return s(r,n),r.include(t.Hover),r.prototype.hoverGetPosition=function(e){var n,r,i;return i=t.Hover.hoverGetPosition.call(this,e),n=i[0],r=i[1],[n,(this.top+this.bottom)/2-this.hoverHeight/2]},r.prototype.init=function(){return this.hoverConfigure(this.options.hoverOptions)},r.prototype.postInit=function(){return this.hoverInit()},r.prototype.defaults={barSizeRatio:.75,barGap:3,barColors:["#0b62a4","#7a92a3","#4da74d","#afd8f8","#edc240","#cb4b4b","#9440ed"]},r.prototype.calc=function(){return this.calcBars(),this.hoverCalculateMargins()},r.prototype.calcBars=function(){var e,t,n,r,i,s,o;s=this.data,o=[];for(e=r=0,i=s.length;ra;e=0<=a?++u:--u)i=this.data[this.data.length-1-e],t=this.r.text(i._x,o,i.label).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor),n=t.getBBox(),(r==null||r>=n.x+n.width)&&n.x>=0&&n.x+n.width=0?this.transY(0):null,this.bars=function(){var o,h,p,d;p=this.data,d=[];for(r=o=0,h=p.length;oMath.PI?1:0,this.path=this.calcSegment(this.inner+3,this.inner+this.outer-5),this.selectedPath=this.calcSegment(this.inner+3,this.inner+this.outer),this.hilight=this.calcArc(this.inner)}return s(t,e),t.prototype.calcArcPoints=function(e){return[this.cx+e*this.sin_p0,this.cy+e*this.cos_p0,this.cx+e*this.sin_p1,this.cy+e*this.cos_p1]},t.prototype.calcSegment=function(e,t){var n,r,i,s,o,u,a,f,l,c;return l=this.calcArcPoints(e),n=l[0],i=l[1],r=l[2],s=l[3],c=this.calcArcPoints(t),o=c[0],a=c[1],u=c[2],f=c[3],"M"+n+","+i+("A"+e+","+e+",0,"+this.long+",0,"+r+","+s)+("L"+u+","+f)+("A"+t+","+t+",0,"+this.long+",1,"+o+","+a)+"Z"},t.prototype.calcArc=function(e){var t,n,r,i,s;return s=this.calcArcPoints(e),t=s[0],r=s[1],n=s[2],i=s[3],"M"+t+","+r+("A"+e+","+e+",0,"+this.long+",0,"+n+","+i)},t.prototype.render=function(e){var t=this;return this.arc=e.path(this.hilight).attr({stroke:this.color,"stroke-width":2,opacity:0}),this.seg=e.path(this.path).attr({fill:this.color,stroke:"white","stroke-width":3}).hover(function(){return t.fire("hover",t)})},t.prototype.select=function(){if(!this.selected)return this.seg.animate({path:this.selectedPath},150,"<>"),this.arc.animate({opacity:1},150,"<>"),this.selected=!0},t.prototype.deselect=function(){if(this.selected)return this.seg.animate({path:this.path},150,"<>"),this.arc.animate({opacity:0},150,"<>"),this.selected=!1},t}(t.EventEmitter)}).call(this);
\ No newline at end of file
diff --git a/package.json b/package.json
index 969e9dc..b23a0eb 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
},
"devDependencies": {
"grunt-coffee": "~> 0.0.6",
- "grunt-mocha": "~> 0.1.7"
+ "grunt-mocha": "~> 0.1.7",
+ "grunt-less": "~> 0.1.7"
}
}
diff --git a/spec/lib/line/line_spec.coffee b/spec/lib/line/line_spec.coffee
index e540da7..8c0115f 100644
--- a/spec/lib/line/line_spec.coffee
+++ b/spec/lib/line/line_spec.coffee
@@ -29,9 +29,8 @@ describe 'Morris.Line', ->
chart.strokeForSeries(0).should.equal red
chart.strokeWidthForSeries(1).should.equal 2
chart.strokeForSeries(1).should.equal blue
- (null == chart.pointFillColorForSeries(0)).should.be
- (chart.pointFillColorForSeries(0) || chart.colorForSeries(0)).should.equal chart.colorForSeries(0)
- chart.pointFillColorForSeries(1).should.equal red
+ chart.colorFor(chart.data[0], 0, 'point').should.equal chart.colorFor(chart.data[0], 0, 'line')
+ chart.colorFor(chart.data[1], 1, 'point').should.equal red
describe 'generating column labels', ->