Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
"./morris.css"
],
"dependencies": {
"jquery": ">= 1.7.0",
"raphael": ">= 2.0"
},
"devDependencies": {
"jquery": ">= 1.7.0",
"mocha": "~1.17.1",
"chai": "~1.9.0",
"chai-jquery": "~1.2.1",
Expand Down
2 changes: 1 addition & 1 deletion lib/morris.area.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class Morris.Area extends Morris.Line

constructor: (options) ->
return new Morris.Area(options) unless (@ instanceof Morris.Area)
areaOptions = $.extend {}, areaDefaults, options
areaOptions = Morris.extend {}, areaDefaults, options

@cumulative = not areaOptions.behaveLikeLine

Expand Down
8 changes: 4 additions & 4 deletions lib/morris.bar.coffee
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
class Morris.Bar extends Morris.Grid
constructor: (options) ->
return new Morris.Bar(options) unless (@ instanceof Morris.Bar)
super($.extend {}, options, parseTime: false)
super(Morris.extend {}, options, parseTime: false)

init: ->
@cumulative = @options.stacked
Expand Down Expand Up @@ -91,15 +91,15 @@ class Morris.Bar extends Morris.Grid
Math.cos(angle * Math.PI / 180.0)
label.transform("t#{offset},0...")


{width, height} = Morris.dimensions @el
if not @options.horizontal
startPos = labelBox.x
size = labelBox.width
maxSize = @el.width()
maxSize = width
else
startPos = labelBox.y
size = labelBox.height
maxSize = @el.height()
maxSize = height

# try to avoid overlaps
if (not prevLabelMargin? or
Expand Down
53 changes: 52 additions & 1 deletion lib/morris.coffee
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Morris = window.Morris = {}

$ = jQuery
# Compute element style
compStyle = (el) ->
if getComputedStyle # standard (includes ie9)
getComputedStyle(el, null)
else if el.currentStyle # IE older
el.currentStyle
else # inline style
el.style

# Very simple event-emitter class.
#
Expand Down Expand Up @@ -41,3 +48,47 @@ Morris.commas = (num) ->
# @example
# Morris.pad2(1) -> '01'
Morris.pad2 = (number) -> (if number < 10 then '0' else '') + number

# Copy all properties from objects in second argument to last onto the first
# object given and return the first object. This should emulate jQuery's
# $.extend().
#
# @example
# Morris.extend({}, { a:1 }, { b:2 }) -> '{ a:1, b:2 }'
Morris.extend = (object={}, objects...) ->
for properties in objects when properties?
for key, val of properties when properties.hasOwnProperty key
object[key] = val
object

# Emulate jQuery's $el.offset() (http://youmightnotneedjquery.com/#offset)
Morris.offset = (el) ->
rect = el.getBoundingClientRect()
top: rect.top + document.body.scrollTop,
left: rect.left + document.body.scrollLeft

# Emulate jQuery's $el.css() (http://youmightnotneedjquery.com/#get_style)
Morris.css = (el, prop) -> compStyle(el)[prop]

# Emulate jQuery's $el.on()
Morris.on = (el, eventName, fn) ->
if el.addEventListener
el.addEventListener(eventName, fn)
else
el.attachEvent('on'+eventName, fn)

# Emulate jQuery's $el.width() and $el.height()
Morris.dimensions = (el) ->
style = compStyle el
width: parseInt(style.width),
height: parseInt(style.height)

# Emulate jQuery's $el.innerWidth() and $el.innerHeight()
Morris.innerDimensions = (el) ->
style = compStyle el
width: parseInt(style.width) +
parseInt(style.paddingLeft) +
parseInt(style.paddingRight),
height: parseInt(style.height) +
parseInt(style.paddingTop) +
parseInt(style.paddingBottom)
21 changes: 12 additions & 9 deletions lib/morris.donut.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ class Morris.Donut extends Morris.EventEmitter
#
constructor: (options) ->
return new Morris.Donut(options) unless (@ instanceof Morris.Donut)
@options = $.extend {}, @defaults, options
@options = Morris.extend {}, @defaults, options

if typeof options.element is 'string'
@el = $ document.getElementById(options.element)
@el = document.getElementById(options.element)
else
@el = $ options.element
@el = options.element[0] or options.element

if @el == null || @el.length == 0
if @el == null
throw new Error("Graph placeholder not found.")

# bail if there's no data
if options.data is undefined or options.data.length is 0
return

@raphael = new Raphael(@el[0])
@raphael = new Raphael(@el)

if @options.resize
$(window).bind 'resize', (evt) =>
Expand All @@ -59,8 +59,9 @@ class Morris.Donut extends Morris.EventEmitter
redraw: ->
@raphael.clear()

cx = @el.width() / 2
cy = @el.height() / 2
{width, height} = Morris.dimensions @el
cx = width / 2
cy = height / 2
w = (Math.min(cx, cy) - 10) / 3

total = 0
Expand Down Expand Up @@ -117,7 +118,8 @@ class Morris.Donut extends Morris.EventEmitter

# @private
setLabels: (label1, label2) ->
inner = (Math.min(@el.width() / 2, @el.height() / 2) - 10) * 2 / 3
{width, height} = Morris.dimensions(@el)
inner = (Math.min(width / 2, height / 2) - 10) * 2 / 3
maxWidth = 1.8 * inner
maxHeightTop = inner / 2
maxHeightBottom = inner / 3
Expand All @@ -139,7 +141,8 @@ class Morris.Donut extends Morris.EventEmitter

resizeHandler: =>
@timeoutId = null
@raphael.setSize @el.width(), @el.height()
{width, height} = Morris.dimensions @el
@raphael.setSize width, height
@redraw()


Expand Down
48 changes: 24 additions & 24 deletions lib/morris.grid.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ class Morris.Grid extends Morris.EventEmitter
constructor: (options) ->
# find the container to draw the graph in
if typeof options.element is 'string'
@el = $ document.getElementById(options.element)
@el = document.getElementById(options.element)
else
@el = $ options.element
if not @el? or @el.length == 0
@el = options.element[0] or options.element
if not @el?
throw new Error("Graph container element not found")

if @el.css('position') == 'static'
@el.css('position', 'relative')
if Morris.css(@el, 'position') == 'static'
@el.style.position = 'relative'

@options = $.extend {}, @gridDefaults, (@defaults || {}), options
@options = Morris.extend {}, @gridDefaults, (@defaults || {}), options

# backwards compatibility for units -> postUnits
if typeof @options.units is 'string'
@options.postUnits = options.units

# the raphael drawing instance
@raphael = new Raphael(@el[0])
@raphael = new Raphael(@el)

# some redraw stuff
@elementWidth = null
Expand All @@ -39,8 +39,8 @@ class Morris.Grid extends Morris.EventEmitter
@setData @options.data

# hover
@el.bind 'mousemove', (evt) =>
offset = @el.offset()
Morris.on @el, 'mousemove', (evt) =>
offset = Morris.offset(@el)
x = evt.pageX - offset.left
if @selectFrom
left = @data[@hitTest(Math.min(x, @selectFrom))]._x
Expand All @@ -50,44 +50,44 @@ class Morris.Grid extends Morris.EventEmitter
else
@fire 'hovermove', x, evt.pageY - offset.top

@el.bind 'mouseleave', (evt) =>
Morris.on @el, 'mouseleave', (evt) =>
if @selectFrom
@selectionRect.hide()
@selectFrom = null
@fire 'hoverout'

@el.bind 'touchstart touchmove touchend', (evt) =>
Morris.on @el, 'touchstart touchmove touchend', (evt) =>
touch = evt.originalEvent.touches[0] or evt.originalEvent.changedTouches[0]
offset = @el.offset()
offset = Morris.offset(@el)
@fire 'hovermove', touch.pageX - offset.left, touch.pageY - offset.top

@el.bind 'click', (evt) =>
offset = @el.offset()
Morris.on @el, 'click', (evt) =>
offset = Morris.offset(@el)
@fire 'gridclick', evt.pageX - offset.left, evt.pageY - offset.top

if @options.rangeSelect
@selectionRect = @raphael.rect(0, 0, 0, @el.innerHeight())
@selectionRect = @raphael.rect(0, 0, 0, Morris.innerDimensions(@el).height)
.attr({ fill: @options.rangeSelectColor, stroke: false })
.toBack()
.hide()

@el.bind 'mousedown', (evt) =>
offset = @el.offset()
Morris.on @el, 'mousedown', (evt) =>
offset = Morris.offset(@el)
@startRange evt.pageX - offset.left

@el.bind 'mouseup', (evt) =>
offset = @el.offset()
Morris.on @el, 'mouseup', (evt) =>
offset = Morris.offset(@el)
@endRange evt.pageX - offset.left
@fire 'hovermove', evt.pageX - offset.left, evt.pageY - offset.top

if @options.resize
$(window).bind 'resize', (evt) =>
Morris.on window, 'resize', (evt) =>
if @timeoutId?
window.clearTimeout @timeoutId
@timeoutId = window.setTimeout @resizeHandler, 100

# Disable tap highlight on iOS.
@el.css('-webkit-tap-highlight-color', 'rgba(0,0,0,0)')
@el.style.webkitTapHighlightColor = 'rgba(0,0,0,0)'

@postInit() if @postInit

Expand Down Expand Up @@ -271,8 +271,7 @@ class Morris.Grid extends Morris.EventEmitter
grid

_calc: ->
w = @el.width()
h = @el.height()
{width:w, height:h} = Morris.dimensions @el

if @elementWidth != w or @elementHeight != h or @dirty
@elementWidth = w
Expand Down Expand Up @@ -482,7 +481,8 @@ class Morris.Grid extends Morris.EventEmitter

resizeHandler: =>
@timeoutId = null
@raphael.setSize @el.width(), @el.height()
{width, height} = Morris.dimensions @el
@raphael.setSize width, height
@redraw()

hasToShow: (i) =>
Expand Down
26 changes: 14 additions & 12 deletions lib/morris.hover.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ class Morris.Hover
class: 'morris-hover morris-default-style'

constructor: (options = {}) ->
@options = $.extend {}, Morris.Hover.defaults, options
@el = $ "<div class='#{@options.class}'></div>"
@el.hide()
@options.parent.append(@el)
@options = Morris.extend {}, Morris.Hover.defaults, options
@el = document.createElement 'div'
@el.className = @options.class
@el.style.display = 'none'
(@options.parent = @options.parent[0] or @options.parent).appendChild @el

update: (html, x, y, centre_y) ->
if not html
Expand All @@ -19,13 +20,13 @@ class Morris.Hover
@moveTo(x, y, centre_y)

html: (content) ->
@el.html(content)
@el.innerHTML = content

moveTo: (x, y, centre_y) ->
parentWidth = @options.parent.innerWidth()
parentHeight = @options.parent.innerHeight()
hoverWidth = @el.outerWidth()
hoverHeight = @el.outerHeight()
{width:parentWidth, height:parentHeight} =
Morris.innerDimensions @options.parent
hoverWidth = @el.offsetWidth
hoverHeight = @el.offsetHeight
left = Math.min(Math.max(0, x - hoverWidth / 2), parentWidth - hoverWidth)
if y?
if centre_y is true
Expand All @@ -40,10 +41,11 @@ class Morris.Hover
top = parentHeight / 2 - hoverHeight / 2
else
top = parentHeight / 2 - hoverHeight / 2
@el.css(left: left + "px", top: parseInt(top) + "px")
@el.style.left = parseInt(left) + "px"
@el.style.top = parseInt(top) + "px"

show: ->
@el.show()
@el.style.display = ''

hide: ->
@el.hide()
@el.style.display = 'none'
5 changes: 3 additions & 2 deletions lib/morris.line.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ class Morris.Line extends Morris.Grid
if (not prevLabelMargin? or
prevLabelMargin >= labelBox.x + labelBox.width or
prevAngleMargin? and prevAngleMargin >= labelBox.x) and
labelBox.x >= 0 and (labelBox.x + labelBox.width) < @el.width()
labelBox.x >= 0 and
(labelBox.x + labelBox.width) < Morris.dimensions(@el).width
if @options.xLabelAngle != 0
margin = 1.25 * @options.gridTextSize /
Math.sin(@options.xLabelAngle * Math.PI / 180.0)
Expand Down Expand Up @@ -392,7 +393,7 @@ Morris.labelSeries = (dmin, dmax, pxwidth, specName, xLabelFormat) ->
spec = Morris.LABEL_SPECS["second"]
# check if there's a user-defined formatting function
if xLabelFormat
spec = $.extend({}, spec, {fmt: xLabelFormat})
spec = Morris.extend({}, spec, {fmt: xLabelFormat})
# calculate labels
d = spec.start(d0)
ret = []
Expand Down
20 changes: 10 additions & 10 deletions spec/lib/hover_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -35,30 +35,30 @@ describe "Morris.Hover", ->

it "should place the popup directly above the given point", ->
@hover.moveTo(100, 150)
@element.should.have.css('left', '50px')
@element.should.have.css('top', '40px')
getComputedStyle(@element[0])['left'].should.be '50px'
getComputedStyle(@element[0])['top'].should.be '40px'

it "should place the popup below the given point if it does not fit above", ->
@hover.moveTo(100, 50)
@element.should.have.css('left', '50px')
@element.should.have.css('top', '60px')
getComputedStyle(@element[0])['left'].should.be '50px'
getComputedStyle(@element[0])['top'].should.be '60px'

it "should center the popup vertically if it will not fit above or below", ->
@hover.moveTo(100, 100)
@element.should.have.css('left', '50px')
@element.should.have.css('top', '40px')
getComputedStyle(@element[0])['left'].should.be '50px'
getComputedStyle(@element[0])['top'].should.be '40px'

it "should center the popup vertically if no y value is supplied", ->
@hover.moveTo(100)
@element.should.have.css('left', '50px')
@element.should.have.css('top', '40px')
getComputedStyle(@element[0])['left'].should.be '50px'
getComputedStyle(@element[0])['top'].should.be '40px'

describe "#update", ->
it "should update content, show and reposition the popup", ->
hover = new Morris.Hover(parent: $('#test'))
html = "<div style='width:84px;height:84px'>Hello, Everyone!</div>"
hover.update(html, 150, 200)
el = $('#test .morris-hover')
el.should.have.css('left', '100px')
el.should.have.css('top', '90px')
getComputedStyle(@element[0])['left'].should.be '100px'
getComputedStyle(@element[0])['top'].should.be '90px'
el.should.have.text('Hello, Everyone!')