mirror of
https://github.com/morrisjs/morris.js.git
synced 2024-11-10 21:36:34 +01:00
first version of hover refactored to be 100% html
This commit is contained in:
parent
25698d6664
commit
9bdabf1d0d
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Area charts</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Bar charts</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Bar charts</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Formatting Dates YYYY-MM-DD</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Decimal Data</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Donut Chart</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Donut Chart</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Time Events</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Value Goals</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Formatting Dates with YYYY-MM</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Negative values</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Non-continuous data</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Formatting Non-date Arbitrary X-axis</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Formatting Dates with Quarters</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Timestamps</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Updating data</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Formatting Dates With Weeks</h1>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<script src="lib/example.js"></script>
|
||||
<link rel="stylesheet" href="lib/example.css">
|
||||
<link rel="stylesheet" href="lib/prettify.css">
|
||||
<link rel="stylesheet" href="../morris.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Formatting Dates YYYY</h1>
|
||||
|
15
grunt.js
15
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');
|
||||
};
|
||||
|
19
less/morris.core.less
Normal file
19
less/morris.core.less
Normal file
@ -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; }
|
||||
}
|
@ -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),
|
||||
|
@ -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
|
||||
@hoverConfigure @options.hoverOptions
|
||||
|
||||
postInit: ->
|
||||
@hoverInit()
|
||||
|
||||
# Default configuration
|
||||
#
|
||||
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,20 +46,11 @@ 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
|
||||
#
|
||||
@ -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
|
||||
|
@ -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"
|
||||
]
|
@ -36,6 +36,8 @@ class Morris.Grid extends Morris.EventEmitter
|
||||
# load data
|
||||
@setData @options.data
|
||||
|
||||
@postInit() if @postInit
|
||||
|
||||
# Default options
|
||||
#
|
||||
gridDefaults:
|
||||
|
113
lib/morris.hover.coffee
Normal file
113
lib/morris.hover.coffee
Normal file
@ -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 = $ "<div/>"
|
||||
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 = $ "<h4/>"
|
||||
xLabel.text row.label
|
||||
xLabel.appendTo @hover
|
||||
for y, i in row.y
|
||||
yLabel = $ "<p/>"
|
||||
yLabel.css "color", @colorFor(row, i, "hover")
|
||||
yLabel.text "#{@options.labels[i]}: #{@yLabelFormat(y)}"
|
||||
yLabel.appendTo @hover
|
@ -1,4 +1,6 @@
|
||||
class Morris.Line extends Morris.Grid
|
||||
@include Morris.Hover
|
||||
|
||||
# Initialise the graph.
|
||||
#
|
||||
constructor: (options) ->
|
||||
@ -9,11 +11,15 @@ 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
|
||||
if @options.hilight
|
||||
@prevHilight = null
|
||||
@el.mousemove (evt) =>
|
||||
@updateHilight evt.pageX
|
||||
if @options.hideHover
|
||||
if @options.hilightAutoHide
|
||||
@el.mouseout (evt) =>
|
||||
@hilight null
|
||||
touchHandler = (evt) =>
|
||||
@ -24,6 +30,9 @@ class Morris.Line extends Morris.Grid
|
||||
@el.bind 'touchmove', touchHandler
|
||||
@el.bind 'touchend', touchHandler
|
||||
|
||||
postInit: ->
|
||||
@hoverInit()
|
||||
|
||||
# Default configuration
|
||||
#
|
||||
defaults:
|
||||
@ -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]
|
2
morris.css
Normal file
2
morris.css
Normal file
@ -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;}
|
765
morris.js
765
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 = $("<div/>");
|
||||
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 = $("<h4/>");
|
||||
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 = $("<p/>");
|
||||
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,11 +781,13 @@
|
||||
this.pointShrink = Raphael.animation({
|
||||
r: this.options.pointSize
|
||||
}, 25, 'linear');
|
||||
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.hideHover) {
|
||||
if (this.options.hilightAutoHide) {
|
||||
this.el.mouseout(function(evt) {
|
||||
return _this.hilight(null);
|
||||
});
|
||||
@ -463,6 +801,11 @@
|
||||
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;
|
||||
return this.hoverConfigure(this.options.hoverOptions);
|
||||
};
|
||||
this.el.bind('touchstart', touchHandler);
|
||||
this.el.bind('touchmove', touchHandler);
|
||||
return this.el.bind('touchend', touchHandler);
|
||||
|
||||
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') {
|
||||
|
2
morris.min.js
vendored
2
morris.min.js
vendored
File diff suppressed because one or more lines are too long
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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', ->
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user