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
40 changes: 40 additions & 0 deletions examples/step.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!doctype html>
<head>
<script src="../third_party/jquery-1.8.2.min.js"></script>
<script src="../third_party/raphael-2.1.0.min.js"></script>
<script src="../morris.js"></script>
<script src="lib/prettify.js"></script>
<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>Step line chart</h1>
<div id="graph"></div>
<pre id="code" class="prettyprint linenums">
/* data stolen from http://howmanyleft.co.uk/vehicle/jaguar_'e'_type */
var day_data = [
{"period": "2012-10-01", "licensed": 3407, "sorned": 660},
{"period": "2012-09-30", "licensed": 3351, "sorned": 629},
{"period": "2012-09-29", "licensed": 3269, "sorned": 618},
{"period": "2012-09-20", "licensed": 3246, "sorned": 661},
{"period": "2012-09-19", "licensed": 3257, "sorned": 667},
{"period": "2012-09-18", "licensed": 3248, "sorned": 627},
{"period": "2012-09-17", "licensed": 3171, "sorned": 660},
{"period": "2012-09-16", "licensed": 3171, "sorned": 676},
{"period": "2012-09-15", "licensed": 3201, "sorned": 656},
{"period": "2012-09-10", "licensed": 3215, "sorned": 622}
];
Morris.Line({
lineWidth:1,
pointSize:2,
element: 'graph',
lineType:{"sorned":"stepNoRiser","licensed":"smooth"},
data: day_data,
xkey: 'period',
ykeys: ['licensed', 'sorned'],
labels: ['Licensed', 'SORN']
});
</pre>
</body>
28 changes: 22 additions & 6 deletions lib/morris.line.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class Morris.Line extends Morris.Grid
pointStrokeColors: ['#ffffff']
pointFillColors: []
smooth: true
lineType: {}
xLabels: 'auto'
xLabelFormat: null
xLabelMargin: 24
Expand Down Expand Up @@ -118,12 +119,21 @@ class Morris.Line extends Morris.Grid
# @private
generatePaths: ->
@paths = for i in [0...@options.ykeys.length]
# Keep 'smooth' option handling for compatibility
smooth = if typeof @options.smooth is "boolean" then @options.smooth else @options.ykeys[i] in @options.smooth
lineType = if smooth then 'smooth' else 'jagged'
# Handle 'lineType' option
if typeof @options.lineType is "string"
lineType = @options.lineType
else
# Expect something like lineType: {"key1":"jagged","key2":"smooth","key3":"step","key4":"stepNoRiser",}
if @options.lineType[@options.ykeys[i]] isnt undefined
lineType = @options.lineType[@options.ykeys[i]]
coords = ({x: r._x, y: r._y[i]} for r in @data when r._y[i] isnt undefined)
coords = (c for c in coords when c.y isnt null) if @options.continuousLine

if coords.length > 1
Morris.Line.createPath coords, smooth, @bottom
Morris.Line.createPath coords, lineType, @bottom
else
null

Expand Down Expand Up @@ -206,15 +216,15 @@ class Morris.Line extends Morris.Grid
# create a path for a data series
#
# @private
@createPath: (coords, smooth, bottom) ->
@createPath: (coords, lineType, bottom) ->
path = ""
grads = Morris.Line.gradients(coords) if smooth
grads = Morris.Line.gradients(coords) if lineType == 'smooth'

prevCoord = {y: null}
for coord, i in coords
if coord.y?
if prevCoord.y?
if smooth
if lineType == 'smooth'
g = grads[i]
lg = grads[i - 1]
ix = (coord.x - prevCoord.x) / 4
Expand All @@ -223,10 +233,16 @@ class Morris.Line extends Morris.Grid
x2 = coord.x - ix
y2 = Math.min(bottom, coord.y - ix * g)
path += "C#{x1},#{y1},#{x2},#{y2},#{coord.x},#{coord.y}"
else
else if lineType == 'jagged'
path += "L#{coord.x},#{coord.y}"
else if lineType == 'step'
path += "L#{coord.x},#{prevCoord.y}"
path += "L#{coord.x},#{coord.y}"
else if lineType == 'stepNoRiser'
path += "L#{coord.x},#{prevCoord.y}"
path += "M#{coord.x},#{coord.y}"
else
if not smooth or grads[i]?
if lineType != 'smooth' or grads[i]?
path += "M#{coord.x},#{coord.y}"
prevCoord = coord
return path
Expand Down
29 changes: 22 additions & 7 deletions morris.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions morris.min.js

Large diffs are not rendered by default.

20 changes: 15 additions & 5 deletions spec/lib/line/line_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -123,29 +123,39 @@ describe 'Morris.Line', ->

it 'should generate a smooth line', ->
testData = [{x: 0, y: 10}, {x: 10, y: 0}, {x: 20, y: 10}]
path = Morris.Line.createPath(testData, true, 20)
path = Morris.Line.createPath(testData, 'smooth', 20)
path.should.equal 'M0,10C2.5,7.5,7.5,0,10,0C12.5,0,17.5,7.5,20,10'

it 'should generate a jagged line', ->
testData = [{x: 0, y: 10}, {x: 10, y: 0}, {x: 20, y: 10}]
path = Morris.Line.createPath(testData, false, 20)
path = Morris.Line.createPath(testData, 'jagged', 20)
path.should.equal 'M0,10L10,0L20,10'

it 'should prevent paths from descending below the bottom of the chart', ->
testData = [{x: 0, y: 20}, {x: 10, y: 30}, {x: 20, y: 10}]
path = Morris.Line.createPath(testData, true, 30)
path = Morris.Line.createPath(testData, 'smooth', 30)
path.should.equal 'M0,20C2.5,22.5,7.5,30,10,30C12.5,28.75,17.5,15,20,10'

it 'should break the line at null values', ->
testData = [{x: 0, y: 10}, {x: 10, y: 0}, {x: 20, y: null}, {x: 30, y: 10}, {x: 40, y: 0}]
path = Morris.Line.createPath(testData, true, 20)
path = Morris.Line.createPath(testData, 'smooth', 20)
path.should.equal 'M0,10C2.5,7.5,7.5,2.5,10,0M30,10C32.5,7.5,37.5,2.5,40,0'

it 'should ignore leading and trailing null values', ->
testData = [{x: 0, y: null}, {x: 10, y: 10}, {x: 20, y: 0}, {x: 30, y: 10}, {x: 40, y: null}]
path = Morris.Line.createPath(testData, true, 20)
path = Morris.Line.createPath(testData, 'smooth', 20)
path.should.equal 'M10,10C12.5,7.5,17.5,0,20,0C22.5,0,27.5,7.5,30,10'

it 'should generate a step line with risers', ->
testData = [{x: 0, y: null}, {x: 10, y: 10}, {x: 20, y: 0}, {x: 30, y: 10}, {x: 40, y: null}]
path = Morris.Line.createPath(testData, 'step', 20)
path.should.equal 'M10,10L20,10L20,0L30,0L30,10'

it 'should generate a step line with no risers', ->
testData = [{x: 0, y: null}, {x: 10, y: 10}, {x: 20, y: 0}, {x: 30, y: 10}, {x: 40, y: null}]
path = Morris.Line.createPath(testData, 'stepNoRiser', 20)
path.should.equal 'M10,10L20,10M20,0L30,0M30,10'

describe 'svg structure', ->
defaults =
element: 'graph'
Expand Down