mirror of
https://github.com/morrisjs/morris.js.git
synced 2024-11-10 21:36:34 +01:00
Add perceptual diffs.
Uses perceptualdiff to catch regressions / changes in charts as they are displayed by a browser (in this case, phantomjs). Currently has exemplaries for basic line, area, bar and stacked bar charts.
This commit is contained in:
parent
68aa4c36f2
commit
063957657c
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
build/
|
||||
node_modules/
|
||||
spec/viz/output/
|
||||
spec/viz/diff/
|
||||
|
15
Gruntfile.js
15
Gruntfile.js
@ -58,7 +58,18 @@ module.exports = function (grunt) {
|
||||
tasks: ['concat:build/morris.coffee', 'coffee:lib']
|
||||
}
|
||||
},
|
||||
shell: {
|
||||
visual_spec: {
|
||||
command: './run.sh',
|
||||
options: {
|
||||
stdout: true,
|
||||
execOptions: {
|
||||
cwd: 'spec/viz'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask('default', ['concat', 'coffee', 'less', 'uglify', 'mocha']);
|
||||
};
|
||||
grunt.registerTask('default', ['concat', 'coffee', 'less', 'uglify', 'mocha', 'shell:visual_spec']);
|
||||
};
|
||||
|
@ -63,4 +63,4 @@ class Morris.Area extends Morris.Line
|
||||
@raphael.path(path)
|
||||
.attr('fill', fill)
|
||||
.attr('fill-opacity', @options.fillOpacity)
|
||||
.attr('stroke-width', 0)
|
||||
.attr('stroke', 'none')
|
||||
|
@ -192,8 +192,8 @@ class Morris.Bar extends Morris.Grid
|
||||
path = @raphael.path @roundedRect(xPos, yPos, width, height, radiusArray)
|
||||
path
|
||||
.attr('fill', barColor)
|
||||
.attr('stroke-width', 0)
|
||||
.attr('fill-opacity', opacity)
|
||||
.attr('stroke', 'none')
|
||||
|
||||
roundedRect: (x, y, w, h, r = [0,0,0,0]) ->
|
||||
[ "M", x, r[0] + y, "Q", x, y, x + r[0], y,
|
||||
|
@ -1372,7 +1372,7 @@
|
||||
};
|
||||
|
||||
Area.prototype.drawFilledPath = function(path, fill) {
|
||||
return this.raphael.path(path).attr('fill', fill).attr('fill-opacity', this.options.fillOpacity).attr('stroke-width', 0);
|
||||
return this.raphael.path(path).attr('fill', fill).attr('fill-opacity', this.options.fillOpacity).attr('stroke', 'none');
|
||||
};
|
||||
|
||||
return Area;
|
||||
@ -1609,7 +1609,7 @@
|
||||
} else {
|
||||
path = this.raphael.path(this.roundedRect(xPos, yPos, width, height, radiusArray));
|
||||
}
|
||||
return path.attr('fill', barColor).attr('stroke-width', 0).attr('fill-opacity', opacity);
|
||||
return path.attr('fill', barColor).attr('fill-opacity', opacity).attr('stroke', 'none');
|
||||
};
|
||||
|
||||
Bar.prototype.roundedRect = function(x, y, w, h, r) {
|
||||
|
2
morris.min.js
vendored
2
morris.min.js
vendored
File diff suppressed because one or more lines are too long
@ -22,7 +22,8 @@
|
||||
"grunt-contrib-coffee": "~0.7.0",
|
||||
"grunt-contrib-uglify": "~0.2.4",
|
||||
"grunt-contrib-less": "~0.7.0",
|
||||
"grunt-contrib-watch": "~0.5.3"
|
||||
"grunt-contrib-watch": "~0.5.3",
|
||||
"grunt-shell": "~0.5.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt concat coffee mocha"
|
||||
|
@ -37,9 +37,9 @@ describe 'Morris.Bar', ->
|
||||
chart = Morris.Bar $.extend {}, defaults
|
||||
$('#graph').find("rect[fill='#0b62a4']").size().should.equal 2
|
||||
|
||||
it 'should have a bar with stroke width 0', ->
|
||||
it 'should have a bar with no stroke', ->
|
||||
chart = Morris.Bar $.extend {}, defaults
|
||||
$('#graph').find("rect[stroke-width='0']").size().should.equal 4
|
||||
$('#graph').find("rect[stroke='none']").size().should.equal 4
|
||||
|
||||
it 'should have text with configured fill color', ->
|
||||
chart = Morris.Bar $.extend {}, defaults
|
||||
|
56
spec/viz/examples.js
Normal file
56
spec/viz/examples.js
Normal file
@ -0,0 +1,56 @@
|
||||
var webpage = require("webpage"),
|
||||
fs = require("fs");
|
||||
|
||||
var html_path = fs.absolute("test.html");
|
||||
var examples = [];
|
||||
|
||||
function run_example(example_index) {
|
||||
if (example_index >= examples.length) {
|
||||
phantom.exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
var example = examples[example_index];
|
||||
var snapshot_index = 0;
|
||||
var page = webpage.create();
|
||||
|
||||
page.viewportSize = { width: 500, height: 300 };
|
||||
page.clipRect = { width: 500, height: 300 };
|
||||
page.onAlert = function (msg) {
|
||||
var e = JSON.parse(msg);
|
||||
if (e.fn == "snapshot") {
|
||||
page.render("output/" + example.name + snapshot_index + ".png");
|
||||
snapshot_index += 1;
|
||||
} else if (e.fn == "mousemove") {
|
||||
page.sendEvent("mousemove", e.x, e.y);
|
||||
}
|
||||
};
|
||||
|
||||
page.open(html_path, function (status) {
|
||||
if (status == "fail") {
|
||||
console.log("Failed to load test page: " + example.name);
|
||||
phantom.exit(1);
|
||||
} else {
|
||||
page.evaluate(example.runner);
|
||||
}
|
||||
page.close();
|
||||
run_example(example_index + 1);
|
||||
});
|
||||
}
|
||||
|
||||
exports.def = function (name, runner) {
|
||||
examples.push({ name: name, runner: runner });
|
||||
};
|
||||
|
||||
exports.run = function () {
|
||||
if (fs.isDirectory("output")) {
|
||||
fs.list("output").forEach(function (path) {
|
||||
if (path != "." && path != "..") {
|
||||
fs.remove("output/" + path);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fs.makeDirectory("output");
|
||||
}
|
||||
run_example(0);
|
||||
};
|
BIN
spec/viz/exemplary/area0.png
Normal file
BIN
spec/viz/exemplary/area0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
spec/viz/exemplary/bar0.png
Normal file
BIN
spec/viz/exemplary/bar0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.8 KiB |
BIN
spec/viz/exemplary/line0.png
Normal file
BIN
spec/viz/exemplary/line0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
spec/viz/exemplary/stacked_bar0.png
Normal file
BIN
spec/viz/exemplary/stacked_bar0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
32
spec/viz/run.sh
Executable file
32
spec/viz/run.sh
Executable file
@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
# visual_specs.js creates output in output/XXX.png
|
||||
phantomjs visual_specs.js
|
||||
|
||||
# clear out old diffs
|
||||
mkdir -p diff
|
||||
rm -f diff/*
|
||||
|
||||
# generate diffs
|
||||
PASS=1
|
||||
for i in exemplary/*.png
|
||||
do
|
||||
FN=`basename $i`
|
||||
perceptualdiff $i output/$FN -output diff/$FN
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
echo "OK: $FN"
|
||||
else
|
||||
echo "FAIL: $FN"
|
||||
PASS=0
|
||||
fi
|
||||
done
|
||||
|
||||
# pass / fail
|
||||
if [ $PASS -eq 1 ]
|
||||
then
|
||||
echo "Success."
|
||||
else
|
||||
echo "Failed."
|
||||
exit 1
|
||||
fi
|
32
spec/viz/test.html
Normal file
32
spec/viz/test.html
Normal file
@ -0,0 +1,32 @@
|
||||
<!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>
|
||||
<link rel="stylesheet" href="../../morris.css">
|
||||
<style>
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: white;
|
||||
}
|
||||
#chart {
|
||||
width: 500px;
|
||||
height: 300px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function bridge(e) {
|
||||
window.alert(JSON.stringify(e));
|
||||
}
|
||||
window.snapshot = function () {
|
||||
bridge({ fn: "snapshot" });
|
||||
};
|
||||
window.mousemove = function (x, y) {
|
||||
bridge({ fn: "mousemove", x: x, y: y });
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="chart"></div>
|
||||
</body>
|
66
spec/viz/visual_specs.js
Normal file
66
spec/viz/visual_specs.js
Normal file
@ -0,0 +1,66 @@
|
||||
var examples = require('./examples');
|
||||
|
||||
examples.def('line', function () {
|
||||
Morris.Line({
|
||||
element: 'chart',
|
||||
data: [
|
||||
{ x: 0, y: 10, z: 30 }, { x: 1, y: 20, z: 20 },
|
||||
{ x: 2, y: 30, z: 10 }, { x: 3, y: 30, z: 10 },
|
||||
{ x: 4, y: 20, z: 20 }, { x: 5, y: 10, z: 30 }
|
||||
],
|
||||
xkey: 'x',
|
||||
ykeys: ['y', 'z'],
|
||||
labels: ['y', 'z'],
|
||||
parseTime: false
|
||||
});
|
||||
window.snapshot();
|
||||
});
|
||||
|
||||
examples.def('area', function () {
|
||||
Morris.Area({
|
||||
element: 'chart',
|
||||
data: [
|
||||
{ x: 0, y: 1, z: 1 }, { x: 1, y: 2, z: 1 },
|
||||
{ x: 2, y: 3, z: 1 }, { x: 3, y: 3, z: 1 },
|
||||
{ x: 4, y: 2, z: 1 }, { x: 5, y: 1, z: 1 }
|
||||
],
|
||||
xkey: 'x',
|
||||
ykeys: ['y', 'z'],
|
||||
labels: ['y', 'z'],
|
||||
parseTime: false
|
||||
});
|
||||
window.snapshot();
|
||||
});
|
||||
|
||||
examples.def('bar', function () {
|
||||
Morris.Bar({
|
||||
element: 'chart',
|
||||
data: [
|
||||
{ x: 0, y: 1, z: 3 }, { x: 1, y: 2, z: 2 },
|
||||
{ x: 2, y: 3, z: 1 }, { x: 3, y: 3, z: 1 },
|
||||
{ x: 4, y: 2, z: 2 }, { x: 5, y: 1, z: 3 }
|
||||
],
|
||||
xkey: 'x',
|
||||
ykeys: ['y', 'z'],
|
||||
labels: ['y', 'z']
|
||||
});
|
||||
window.snapshot();
|
||||
});
|
||||
|
||||
examples.def('stacked_bar', function () {
|
||||
Morris.Bar({
|
||||
element: 'chart',
|
||||
data: [
|
||||
{ x: 0, y: 1, z: 1 }, { x: 1, y: 2, z: 1 },
|
||||
{ x: 2, y: 3, z: 1 }, { x: 3, y: 3, z: 1 },
|
||||
{ x: 4, y: 2, z: 1 }, { x: 5, y: 1, z: 1 }
|
||||
],
|
||||
xkey: 'x',
|
||||
ykeys: ['y', 'z'],
|
||||
labels: ['y', 'z'],
|
||||
stacked: true
|
||||
});
|
||||
window.snapshot();
|
||||
});
|
||||
|
||||
examples.run();
|
Loading…
Reference in New Issue
Block a user