mirror of
https://github.com/morrisjs/morris.js.git
synced 2024-11-14 07:41:11 +01:00
draw functionality broken out into methods on each class
This commit is contained in:
parent
14c56165c6
commit
32b06226c2
7 changed files with 102 additions and 109 deletions
|
@ -26,7 +26,7 @@ class Morris.Area extends Morris.Line
|
||||||
path = @paths[i]
|
path = @paths[i]
|
||||||
if path isnt null
|
if path isnt null
|
||||||
path = path + "L#{@transX(@xmax)},#{@bottom}L#{@transX(@xmin)},#{@bottom}Z"
|
path = path + "L#{@transX(@xmax)},#{@bottom}L#{@transX(@xmin)},#{@bottom}Z"
|
||||||
@morrisSVG.drawFilledPath(path, @fillForSeries(i))
|
@drawFilledPath(path, @fillForSeries(i))
|
||||||
super()
|
super()
|
||||||
|
|
||||||
fillForSeries: (i) ->
|
fillForSeries: (i) ->
|
||||||
|
@ -35,3 +35,8 @@ class Morris.Area extends Morris.Line
|
||||||
color.h,
|
color.h,
|
||||||
Math.min(255, color.s * 0.75),
|
Math.min(255, color.s * 0.75),
|
||||||
Math.min(255, color.l * 1.25))
|
Math.min(255, color.l * 1.25))
|
||||||
|
|
||||||
|
drawFilledPath: (path, fill) ->
|
||||||
|
@raphael.path(path)
|
||||||
|
.attr('fill', fill)
|
||||||
|
.attr('stroke-width', 0)
|
||||||
|
|
|
@ -59,7 +59,7 @@ class Morris.Bar extends Morris.Grid
|
||||||
prevLabelMargin = null
|
prevLabelMargin = null
|
||||||
for i in [0...@data.length]
|
for i in [0...@data.length]
|
||||||
row = @data[@data.length - 1 - i]
|
row = @data[@data.length - 1 - i]
|
||||||
label = @morrisSVG.drawXAxisLabel(row._x, ypos, row.label)
|
label = @drawXAxisLabel(row._x, ypos, row.label)
|
||||||
labelBox = label.getBBox()
|
labelBox = label.getBBox()
|
||||||
# ensure a minimum of `xLabelMargin` pixels between labels, and ensure
|
# ensure a minimum of `xLabelMargin` pixels between labels, and ensure
|
||||||
# labels don't overflow the container
|
# labels don't overflow the container
|
||||||
|
@ -94,7 +94,7 @@ class Morris.Bar extends Morris.Grid
|
||||||
size = bottom - top
|
size = bottom - top
|
||||||
|
|
||||||
top -= lastTop if @options.stacked
|
top -= lastTop if @options.stacked
|
||||||
@morrisSVG.drawBar(left, top, barWidth, size, @colorFor(row, sidx, 'bar'))
|
@drawBar(left, top, barWidth, size, @colorFor(row, sidx, 'bar'))
|
||||||
|
|
||||||
lastTop += size
|
lastTop += size
|
||||||
else
|
else
|
||||||
|
@ -152,3 +152,13 @@ class Morris.Bar extends Morris.Grid
|
||||||
"""
|
"""
|
||||||
x = @left + (index + 0.5) * @width / @data.length
|
x = @left + (index + 0.5) * @width / @data.length
|
||||||
[content, x]
|
[content, x]
|
||||||
|
|
||||||
|
drawXAxisLabel: (xPos, yPos, text) ->
|
||||||
|
label = @raphael.text(xPos, yPos, text)
|
||||||
|
.attr('font-size', @options.gridTextSize)
|
||||||
|
.attr('fill', @options.gridTextColor)
|
||||||
|
|
||||||
|
drawBar: (xPos, yPos, width, height, barColor) ->
|
||||||
|
@raphael.rect(xPos, yPos, width, height)
|
||||||
|
.attr('fill', barColor)
|
||||||
|
.attr('stroke-width', 0)
|
||||||
|
|
|
@ -54,7 +54,7 @@ class Morris.Donut
|
||||||
redraw: ->
|
redraw: ->
|
||||||
@el.empty()
|
@el.empty()
|
||||||
|
|
||||||
@morrisSVG = new Morris.SVG(@el[0], @options)
|
@raphael = new Raphael(@el[0])
|
||||||
|
|
||||||
cx = @el.width() / 2
|
cx = @el.width() / 2
|
||||||
cy = @el.height() / 2
|
cy = @el.height() / 2
|
||||||
|
@ -71,14 +71,14 @@ class Morris.Donut
|
||||||
@segments = []
|
@segments = []
|
||||||
for d in @data
|
for d in @data
|
||||||
next = last + min + C * (d.value / total)
|
next = last + min + C * (d.value / total)
|
||||||
seg = new Morris.DonutSegment(cx, cy, w*2, w, last, next, @options.colors[idx % @options.colors.length], d)
|
seg = new Morris.DonutSegment(cx, cy, w*2, w, last, next, @options.colors[idx % @options.colors.length], d, @raphael)
|
||||||
seg.render @morrisSVG
|
seg.render()
|
||||||
@segments.push seg
|
@segments.push seg
|
||||||
seg.on 'hover', @select
|
seg.on 'hover', @select
|
||||||
last = next
|
last = next
|
||||||
idx += 1
|
idx += 1
|
||||||
@text1 = @morrisSVG.drawEmptyDonutLabel(cx, cy - 10, 15, 800)
|
@text1 = @drawEmptyDonutLabel(cx, cy - 10, 15, 800)
|
||||||
@text2 = @morrisSVG.drawEmptyDonutLabel(cx, cy + 10, 14)
|
@text2 = @drawEmptyDonutLabel(cx, cy + 10, 14)
|
||||||
max_value = Math.max.apply(null, d.value for d in @data)
|
max_value = Math.max.apply(null, d.value for d in @data)
|
||||||
idx = 0
|
idx = 0
|
||||||
for d in @data
|
for d in @data
|
||||||
|
@ -109,12 +109,17 @@ class Morris.Donut
|
||||||
text2scale = Math.min(maxWidth / text2bbox.width, maxHeightBottom / text2bbox.height)
|
text2scale = Math.min(maxWidth / text2bbox.width, maxHeightBottom / text2bbox.height)
|
||||||
@text2.attr(transform: "S#{text2scale},#{text2scale},#{text2bbox.x + text2bbox.width / 2},#{text2bbox.y}")
|
@text2.attr(transform: "S#{text2scale},#{text2scale},#{text2bbox.x + text2bbox.width / 2},#{text2bbox.y}")
|
||||||
|
|
||||||
|
drawEmptyDonutLabel: (xPos, yPos, fontSize, fontWeight) ->
|
||||||
|
text = @raphael.text(xPos, yPos, '').attr('font-size', fontSize)
|
||||||
|
text.attr('font-weight', fontWeight) if fontWeight?
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
# A segment within a donut chart.
|
# A segment within a donut chart.
|
||||||
#
|
#
|
||||||
# @private
|
# @private
|
||||||
class Morris.DonutSegment extends Morris.EventEmitter
|
class Morris.DonutSegment extends Morris.EventEmitter
|
||||||
constructor: (@cx, @cy, @inner, @outer, p0, p1, @color, @data) ->
|
constructor: (@cx, @cy, @inner, @outer, p0, p1, @color, @data, @raphael) ->
|
||||||
@sin_p0 = Math.sin(p0)
|
@sin_p0 = Math.sin(p0)
|
||||||
@cos_p0 = Math.cos(p0)
|
@cos_p0 = Math.cos(p0)
|
||||||
@sin_p1 = Math.sin(p1)
|
@sin_p1 = Math.sin(p1)
|
||||||
|
@ -147,9 +152,18 @@ class Morris.DonutSegment extends Morris.EventEmitter
|
||||||
"M#{ix0},#{iy0}" +
|
"M#{ix0},#{iy0}" +
|
||||||
"A#{r},#{r},0,#{@long},0,#{ix1},#{iy1}")
|
"A#{r},#{r},0,#{@long},0,#{ix1},#{iy1}")
|
||||||
|
|
||||||
render: (morrisSVG) ->
|
render: ->
|
||||||
@arc = morrisSVG.drawDonutArc(@hilight, @color)
|
@arc = @drawDonutArc(@hilight, @color)
|
||||||
@seg = morrisSVG.drawDonutSegment(@path, @color, => @fire('hover', @))
|
@seg = @drawDonutSegment(@path, @color, => @fire('hover', @))
|
||||||
|
|
||||||
|
drawDonutArc: (path, color) ->
|
||||||
|
@raphael.path(path)
|
||||||
|
.attr(stroke: color, 'stroke-width': 2, opacity: 0)
|
||||||
|
|
||||||
|
drawDonutSegment: (path, color, hoverFunction) ->
|
||||||
|
@raphael.path(path)
|
||||||
|
.attr(fill: color, stroke: 'white', 'stroke-width': 3)
|
||||||
|
.hover(hoverFunction)
|
||||||
|
|
||||||
select: =>
|
select: =>
|
||||||
unless @selected
|
unless @selected
|
||||||
|
|
|
@ -26,8 +26,7 @@ class Morris.Grid extends Morris.EventEmitter
|
||||||
@options.postUnits = options.units
|
@options.postUnits = options.units
|
||||||
|
|
||||||
# the raphael drawing instance
|
# the raphael drawing instance
|
||||||
@r = new Raphael(@el[0])
|
@raphael = new Raphael(@el[0])
|
||||||
@morrisSVG = new Morris.SVG(@el[0], @options)
|
|
||||||
|
|
||||||
# some redraw stuff
|
# some redraw stuff
|
||||||
@elementWidth = null
|
@elementWidth = null
|
||||||
|
@ -228,7 +227,7 @@ class Morris.Grid extends Morris.EventEmitter
|
||||||
# If you need to re-size your charts, call this method after changing the
|
# If you need to re-size your charts, call this method after changing the
|
||||||
# size of the container element.
|
# size of the container element.
|
||||||
redraw: ->
|
redraw: ->
|
||||||
@morrisSVG.clear()
|
@raphael.clear()
|
||||||
@_calc()
|
@_calc()
|
||||||
@drawGrid()
|
@drawGrid()
|
||||||
@drawGoals()
|
@drawGoals()
|
||||||
|
@ -239,12 +238,12 @@ class Morris.Grid extends Morris.EventEmitter
|
||||||
#
|
#
|
||||||
drawGoals: ->
|
drawGoals: ->
|
||||||
for goal, i in @options.goals
|
for goal, i in @options.goals
|
||||||
@morrisSVG.drawGoal("M#{@left},#{@transY(goal)}H#{@left + @width}")
|
@drawGoal("M#{@left},#{@transY(goal)}H#{@left + @width}")
|
||||||
|
|
||||||
# draw events vertical lines
|
# draw events vertical lines
|
||||||
drawEvents: ->
|
drawEvents: ->
|
||||||
for event, i in @events
|
for event, i in @events
|
||||||
@morrisSVG.drawEvent("M#{@transX(event)},#{@bottom}V#{@top}")
|
@drawEvent("M#{@transX(event)},#{@bottom}V#{@top}")
|
||||||
|
|
||||||
# draw y axis labels, horizontal lines
|
# draw y axis labels, horizontal lines
|
||||||
#
|
#
|
||||||
|
@ -256,14 +255,17 @@ class Morris.Grid extends Morris.EventEmitter
|
||||||
v = parseFloat(lineY.toFixed(@precision))
|
v = parseFloat(lineY.toFixed(@precision))
|
||||||
y = @transY(v)
|
y = @transY(v)
|
||||||
if @options.axes
|
if @options.axes
|
||||||
@morrisSVG.drawYAxisLabel(@left - @options.padding / 2, y, @yAxisFormat(v))
|
@drawYAxisLabel(@left - @options.padding / 2, y, @yAxisFormat(v))
|
||||||
if @options.grid
|
if @options.grid
|
||||||
@morrisSVG.drawGridLine("M#{@left},#{y}H#{@left + @width}")
|
@drawGridLine("M#{@left},#{y}H#{@left + @width}")
|
||||||
|
|
||||||
# @private
|
# @private
|
||||||
#
|
#
|
||||||
measureText: (text, fontSize = 12) ->
|
measureText: (text, fontSize = 12) ->
|
||||||
@morrisSVG.measureText(text, fontSize)
|
tt = @raphael.text(100, 100, text).attr('font-size', fontSize)
|
||||||
|
ret = tt.getBBox()
|
||||||
|
tt.remove()
|
||||||
|
ret
|
||||||
|
|
||||||
# @private
|
# @private
|
||||||
#
|
#
|
||||||
|
@ -282,6 +284,27 @@ class Morris.Grid extends Morris.EventEmitter
|
||||||
if hit?
|
if hit?
|
||||||
@hover.update(hit...)
|
@hover.update(hit...)
|
||||||
|
|
||||||
|
drawGoal: (path) ->
|
||||||
|
@raphael.path(path)
|
||||||
|
.attr('stroke', @options.goalLineColors[i % @options.goalLineColors.length])
|
||||||
|
.attr('stroke-width', @options.goalStrokeWidth)
|
||||||
|
|
||||||
|
drawEvent: (path) ->
|
||||||
|
@raphael.path(path)
|
||||||
|
.attr('stroke', @options.eventLineColors[i % @options.eventLineColors.length])
|
||||||
|
.attr('stroke-width', @options.eventStrokeWidth)
|
||||||
|
|
||||||
|
drawYAxisLabel: (xPos, yPos, text) ->
|
||||||
|
@raphael.text(xPos, yPos, text)
|
||||||
|
.attr('font-size', @options.gridTextSize)
|
||||||
|
.attr('fill', @options.gridTextColor)
|
||||||
|
.attr('text-anchor', 'end')
|
||||||
|
|
||||||
|
drawGridLine: (path) ->
|
||||||
|
@raphael.path(path)
|
||||||
|
.attr('stroke', @options.gridLineColor)
|
||||||
|
.attr('stroke-width', @options.gridStrokeWidth)
|
||||||
|
|
||||||
# Parse a date into a javascript timestamp
|
# Parse a date into a javascript timestamp
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
|
@ -138,7 +138,7 @@ class Morris.Line extends Morris.Grid
|
||||||
ypos = @bottom + @options.gridTextSize * 1.25
|
ypos = @bottom + @options.gridTextSize * 1.25
|
||||||
prevLabelMargin = null
|
prevLabelMargin = null
|
||||||
drawLabel = (labelText, xpos) =>
|
drawLabel = (labelText, xpos) =>
|
||||||
label = @morrisSVG.drawXAxisLabel(@transX(xpos), ypos, labelText)
|
label = @drawXAxisLabel(@transX(xpos), ypos, labelText)
|
||||||
labelBox = label.getBBox()
|
labelBox = label.getBBox()
|
||||||
# ensure a minimum of `xLabelMargin` pixels between labels, and ensure
|
# ensure a minimum of `xLabelMargin` pixels between labels, and ensure
|
||||||
# labels don't overflow the container
|
# labels don't overflow the container
|
||||||
|
@ -168,12 +168,12 @@ class Morris.Line extends Morris.Grid
|
||||||
for i in [@options.ykeys.length-1..0]
|
for i in [@options.ykeys.length-1..0]
|
||||||
path = @paths[i]
|
path = @paths[i]
|
||||||
if path isnt null
|
if path isnt null
|
||||||
@morrisSVG.drawLinePath(path, @colorFor(row, i, 'line')) #row isn't available here?
|
@drawLinePath(path, @colorFor(row, i, 'line')) #row isn't available here?
|
||||||
@seriesPoints = ([] for i in [0...@options.ykeys.length])
|
@seriesPoints = ([] for i in [0...@options.ykeys.length])
|
||||||
for i in [@options.ykeys.length-1..0]
|
for i in [@options.ykeys.length-1..0]
|
||||||
for row in @data
|
for row in @data
|
||||||
if row._y[i]?
|
if row._y[i]?
|
||||||
circle = @morrisSVG.drawLinePoint(row._x, row._y[i], @options.pointSize, @colorFor(row, i, 'point'), i)
|
circle = @drawLinePoint(row._x, row._y[i], @options.pointSize, @colorFor(row, i, 'point'), i)
|
||||||
else
|
else
|
||||||
circle = null
|
circle = null
|
||||||
@seriesPoints[i].push(circle)
|
@seriesPoints[i].push(circle)
|
||||||
|
@ -246,6 +246,29 @@ class Morris.Line extends Morris.Grid
|
||||||
else
|
else
|
||||||
@options.lineColors[sidx % @options.lineColors.length]
|
@options.lineColors[sidx % @options.lineColors.length]
|
||||||
|
|
||||||
|
drawXAxisLabel: (xPos, yPos, text) ->
|
||||||
|
@raphael.text(xPos, yPos, text)
|
||||||
|
.attr('font-size', @options.gridTextSize)
|
||||||
|
.attr('fill', @options.gridTextColor)
|
||||||
|
|
||||||
|
drawLinePath: (path, lineColor) ->
|
||||||
|
@raphael.path(path)
|
||||||
|
.attr('stroke', lineColor)
|
||||||
|
.attr('stroke-width', @options.lineWidth)
|
||||||
|
|
||||||
|
drawLinePoint: (xPos, yPos, size, pointColor, lineIndex) ->
|
||||||
|
@raphael.circle(xPos, yPos, size)
|
||||||
|
.attr('fill', pointColor)
|
||||||
|
.attr('stroke-width', @strokeWidthForSeries(lineIndex))
|
||||||
|
.attr('stroke', @strokeForSeries(lineIndex))
|
||||||
|
|
||||||
|
# @private
|
||||||
|
strokeWidthForSeries: (index) ->
|
||||||
|
@options.pointWidths[index % @options.pointWidths.length]
|
||||||
|
|
||||||
|
# @private
|
||||||
|
strokeForSeries: (index) ->
|
||||||
|
@options.pointStrokeColors[index % @options.pointStrokeColors.length]
|
||||||
|
|
||||||
# generate a series of label, timestamp pairs for x-axis labels
|
# generate a series of label, timestamp pairs for x-axis labels
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
class Morris.SVG
|
|
||||||
|
|
||||||
constructor: (element, options) ->
|
|
||||||
@raphael = new Raphael(element)
|
|
||||||
@options = options
|
|
||||||
|
|
||||||
clear: ->
|
|
||||||
@raphael.clear()
|
|
||||||
|
|
||||||
drawGoal: (path) ->
|
|
||||||
@raphael.path(path)
|
|
||||||
.attr('stroke', @options.goalLineColors[i % @options.goalLineColors.length])
|
|
||||||
.attr('stroke-width', @options.goalStrokeWidth)
|
|
||||||
|
|
||||||
drawEvent: (path) ->
|
|
||||||
@raphael.path(path)
|
|
||||||
.attr('stroke', @options.eventLineColors[i % @options.eventLineColors.length])
|
|
||||||
.attr('stroke-width', @options.eventStrokeWidth)
|
|
||||||
|
|
||||||
drawYAxisLabel: (xPos, yPos, text) ->
|
|
||||||
@raphael.text(xPos, yPos, text)
|
|
||||||
.attr('font-size', @options.gridTextSize)
|
|
||||||
.attr('fill', @options.gridTextColor)
|
|
||||||
.attr('text-anchor', 'end')
|
|
||||||
|
|
||||||
drawXAxisLabel: (xPos, yPos, text) ->
|
|
||||||
label = @raphael.text(xPos, yPos, text)
|
|
||||||
.attr('font-size', @options.gridTextSize)
|
|
||||||
.attr('fill', @options.gridTextColor)
|
|
||||||
|
|
||||||
drawGridLine: (path) ->
|
|
||||||
@raphael.path(path)
|
|
||||||
.attr('stroke', @options.gridLineColor)
|
|
||||||
.attr('stroke-width', @options.gridStrokeWidth)
|
|
||||||
|
|
||||||
measureText: (text, fontSize = 12) ->
|
|
||||||
tt = @raphael.text(100, 100, text).attr('font-size', fontSize)
|
|
||||||
ret = tt.getBBox()
|
|
||||||
tt.remove()
|
|
||||||
ret
|
|
||||||
|
|
||||||
drawEmptyDonutLabel: (xPos, yPos, fontSize, fontWeight) ->
|
|
||||||
text = @raphael.text(xPos, yPos, '').attr('font-size', fontSize)
|
|
||||||
text.attr('font-weight', fontWeight) if fontWeight?
|
|
||||||
return text
|
|
||||||
|
|
||||||
drawDonutArc: (path, color) ->
|
|
||||||
@raphael.path(path).attr(stroke: color, 'stroke-width': 2, opacity: 0)
|
|
||||||
|
|
||||||
drawDonutSegment: (path, color, hoverFunction) ->
|
|
||||||
@raphael.path(path)
|
|
||||||
.attr(fill: color, stroke: 'white', 'stroke-width': 3)
|
|
||||||
.hover(hoverFunction)
|
|
||||||
|
|
||||||
drawFilledPath: (path, fill) ->
|
|
||||||
@raphael.path(path)
|
|
||||||
.attr('fill', fill)
|
|
||||||
.attr('stroke-width', 0)
|
|
||||||
|
|
||||||
drawLinePath: (path, lineColor) ->
|
|
||||||
@raphael.path(path)
|
|
||||||
.attr('stroke', lineColor)
|
|
||||||
.attr('stroke-width', @options.lineWidth)
|
|
||||||
|
|
||||||
drawLinePoint: (xPos, yPos, size, pointColor, lineIndex) ->
|
|
||||||
circle = @raphael.circle(xPos, yPos, size)
|
|
||||||
.attr('fill', pointColor)
|
|
||||||
.attr('stroke-width', @strokeWidthForSeries(lineIndex))
|
|
||||||
.attr('stroke', @strokeForSeries(lineIndex))
|
|
||||||
|
|
||||||
drawBar: (xPos, yPos, width, height, barColor) ->
|
|
||||||
@raphael.rect(xPos, yPos, width, height)
|
|
||||||
.attr('fill', barColor)
|
|
||||||
.attr('stroke-width', 0)
|
|
||||||
|
|
||||||
# @private
|
|
||||||
strokeWidthForSeries: (index) ->
|
|
||||||
@options.pointWidths[index % @options.pointWidths.length]
|
|
||||||
|
|
||||||
# @private
|
|
||||||
strokeForSeries: (index) ->
|
|
||||||
@options.pointStrokeColors[index % @options.pointStrokeColors.length]
|
|
|
@ -25,10 +25,10 @@ describe 'Morris.Line', ->
|
||||||
pointStrokeColors: [red, blue]
|
pointStrokeColors: [red, blue]
|
||||||
pointWidths: [1, 2]
|
pointWidths: [1, 2]
|
||||||
pointFillColors: [null, red]
|
pointFillColors: [null, red]
|
||||||
chart.morrisSVG.strokeWidthForSeries(0).should.equal 1
|
chart.strokeWidthForSeries(0).should.equal 1
|
||||||
chart.morrisSVG.strokeForSeries(0).should.equal red
|
chart.strokeForSeries(0).should.equal red
|
||||||
chart.morrisSVG.strokeWidthForSeries(1).should.equal 2
|
chart.strokeWidthForSeries(1).should.equal 2
|
||||||
chart.morrisSVG.strokeForSeries(1).should.equal blue
|
chart.strokeForSeries(1).should.equal blue
|
||||||
chart.colorFor(chart.data[0], 0, 'point').should.equal chart.colorFor(chart.data[0], 0, 'line')
|
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
|
chart.colorFor(chart.data[1], 1, 'point').should.equal red
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue