progress indicators, bug fixes, after a while

This commit is contained in:
Kwesi Banson
2023-12-13 12:13:47 +00:00
parent ea6d83e5d9
commit bc97f69748
1283 changed files with 1010757 additions and 7379 deletions

View File

@@ -0,0 +1,487 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe('drawSeries', function() {
describe('drawSeriesLines', function() {
var minx = 0, maxx = 200, miny = 0, maxy = 100,
series, ctx, plotWidth, plotHeight, plotOffset,
drawSeriesLines = jQuery.plot.drawSeries.drawSeriesLines,
getColorOrGradient;
beforeEach(function() {
series = {
lines: {
lineWidth: 1
},
datapoints: {
format: null,
points: null,
pointsize: 2
},
xaxis: {
min: minx,
max: maxx,
p2c: function(p) { return p; }
},
yaxis: {
min: miny,
max: maxy,
p2c: function(p) { return p; }
}
};
ctx = setFixtures('<div id="test-container" style="width: 200px;height: 100px;border-style: solid;border-width: 1px"><canvas id="theCanvas" style="width: 100%; height: 100%" /></div>')
.find('#theCanvas')[0]
.getContext('2d');
plotWidth = 200;
plotHeight = 100;
plotOffset = { top: 0, left: 0 };
getColorOrGradient = jasmine.createSpy().and.returnValue('rgb(10,200,10)');
});
it('should draw nothing when the values are null', function () {
series.datapoints.points = [null, null, null, null];
spyOn(ctx, 'moveTo').and.callThrough();
spyOn(ctx, 'lineTo').and.callThrough();
drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
expect(ctx.moveTo).not.toHaveBeenCalled();
expect(ctx.lineTo).not.toHaveBeenCalled();
});
it('should draw lines for values', function () {
series.datapoints.points = [0, 0, 150, 25, 50, 75, 200, 100];
spyOn(ctx, 'lineTo').and.callThrough();
drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
expect(ctx.lineTo).toHaveBeenCalled();
});
it('should decimate when a decimate function is provided', function () {
series.datapoints.points = [-1, -1, 0, 0, 1, 1, 2, 2, 3, 3];
series.decimate = function() {
return [0, 0, 1, 1];
};
spyOn(ctx, 'moveTo').and.callThrough();
spyOn(ctx, 'lineTo').and.callThrough();
drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
expect(ctx.moveTo).toHaveBeenCalledWith(0, 0);
expect(ctx.lineTo).toHaveBeenCalledWith(1, 1);
});
it('should clip the lines when the points are outside the range of the axes', function () {
series.datapoints.points = [
minx - 8, 50,
maxx + 8, 50,
100, miny - 8,
100, maxy + 8,
minx - 8, 50];
spyOn(ctx, 'moveTo').and.callThrough();
spyOn(ctx, 'lineTo').and.callThrough();
drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
validatePointsAreInsideTheAxisRanges(
ctx.moveTo.calls.allArgs().concat(
ctx.lineTo.calls.allArgs()));
});
it('should clip the lines and the fill area when the points are outside the range of the axes', function () {
series.datapoints.points = [
minx - 8, 50,
maxx + 8, 50,
100, miny - 8,
100, maxy + 8,
minx - 8, 50];
series.lines.fill = true;
series.lines.fillColor = 'rgb(200, 200, 200)';
spyOn(ctx, 'moveTo').and.callThrough();
spyOn(ctx, 'lineTo').and.callThrough();
drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
validatePointsAreInsideTheAxisRanges(
ctx.moveTo.calls.allArgs().concat(
ctx.lineTo.calls.allArgs()));
});
it('should draw the lines when trailing step interpolation is enabled', function () {
series.datapoints.points = [0, 0, 150, 25, 50, 75, 200, 100];
series.lines.steps = true;
spyOn(ctx, 'lineTo').and.callThrough();
drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
expect(ctx.lineTo).toHaveBeenCalled();
});
it('should fill the area when trailing step interpolation is enabled', function () {
series.datapoints.points = [0, 0, 150, 25, 50, 75, 200, 100];
series.lines.steps = true;
series.lines.fill = true;
series.lines.lineWidth = 0;
spyOn(ctx, 'moveTo').and.callThrough();
spyOn(ctx, 'lineTo').and.callThrough();
spyOn(ctx, 'fill').and.callThrough();
drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
expect(ctx.moveTo).toHaveBeenCalled();
expect(ctx.lineTo).toHaveBeenCalled();
expect(ctx.fill).toHaveBeenCalled();
});
function validatePointsAreInsideTheAxisRanges(points) {
points.forEach(function(point) {
var x = point[0], y = point[1];
expect(minx <= x && x <= maxx).toBe(true);
expect(miny <= y && y <= maxy).toBe(true);
});
}
});
describe('drawSeriesPoints', function() {
var minx = 0, maxx = 200, miny = 0, maxy = 100,
series, ctx, plotWidth, plotHeight, plotOffset,
drawSeriesPoints = jQuery.plot.drawSeries.drawSeriesPoints,
dollar, getColorOrGradient;
beforeEach(function() {
series = {
points: {
show: true,
symbol: 'circle',
radius: 5
},
datapoints: {
format: null,
points: null,
pointsize: 2
},
xaxis: {
min: minx,
max: maxx,
p2c: function(p) { return p; }
},
yaxis: {
min: miny,
max: maxy,
p2c: function(p) { return p; }
}
};
ctx = setFixtures('<div id="test-container" style="width: 200px;height: 100px;border-style: solid;border-width: 1px"><canvas id="theCanvas" style="width: 100%; height: 100%" /></div>')
.find('#theCanvas')[0]
.getContext('2d');
plotWidth = 200;
plotHeight = 100;
plotOffset = { top: 0, left: 0 };
dollar = jasmine.createSpy().and.callFake(function (ctx, x, y, radius, shadow) {
ctx.strokeText('$', x, y);
});
getColorOrGradient = jasmine.createSpy().and.returnValue('rgb(10,200,10)');
});
it('should draw nothing when the values are null', function () {
series.datapoints.points = [null, null, null, null];
spyOn(ctx, 'moveTo').and.callThrough();
spyOn(ctx, 'lineTo').and.callThrough();
drawSeriesPoints(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
expect(ctx.moveTo).not.toHaveBeenCalled();
expect(ctx.lineTo).not.toHaveBeenCalled();
});
it('should draw circles by default for values', function () {
series.datapoints.points = [0, 0, 150, 25, 50, 75, 200, 100];
spyOn(ctx, 'arc').and.callThrough();
drawSeriesPoints(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
expect(ctx.arc).toHaveBeenCalled();
});
it('should draw custom symbols given by name for values', function () {
series.points.symbol = 'dollar';
series.datapoints.points = [0, 0, 150, 25, 50, 75, 200, 100];
drawSeriesPoints(series, ctx, plotOffset, plotWidth, plotHeight, {'dollar': dollar}, getColorOrGradient);
expect(dollar).toHaveBeenCalled();
});
it('should draw custom symbols given by function for values', function () {
series.points.symbol = 'dollar';
series.datapoints.points = [0, 0, 150, 25, 50, 75, 200, 100];
drawSeriesPoints(series, ctx, plotOffset, plotWidth, plotHeight, dollar, getColorOrGradient);
expect(dollar).toHaveBeenCalled();
});
it('should not fill when the symbol function doesn`t need fill', function () {
dollar.fill = undefined;
series.points.symbol = 'dollar';
series.datapoints.points = [0, 0, 150, 25, 50, 75, 200, 100];
spyOn(ctx, 'fill').and.callThrough();
drawSeriesPoints(series, ctx, plotOffset, plotWidth, plotHeight, dollar, getColorOrGradient);
expect(ctx.fill).not.toHaveBeenCalled();
});
it('should fill only once when the symbol function needs fill', function () {
dollar.fill = true;
series.points.symbol = 'dollar';
series.datapoints.points = [0, 0, 150, 25, 50, 75, 200, 100];
spyOn(ctx, 'fill').and.callThrough();
drawSeriesPoints(series, ctx, plotOffset, plotWidth, plotHeight, dollar, getColorOrGradient);
expect(ctx.fill).toHaveBeenCalled();
expect(ctx.fill.calls.count()).toBe(1);
});
});
describe('drawSeriesBars', function() {
var minx = -200, maxx = 200, miny = -100, maxy = 100,
series, ctx, plotWidth, plotHeight, plotOffset,
drawSeriesBars = jQuery.plot.drawSeries.drawSeriesBars,
getColorOrGradient;
beforeEach(function() {
series = {
bars: {
lineWidth: 1,
show: true,
fillColor: 'blue',
barWidth: 0.8
},
datapoints: {
format: null,
points: null,
pointsize: 2
},
xaxis: {
min: minx,
max: maxx,
autoScale: 'exact',
p2c: function(p) { return p; }
},
yaxis: {
min: miny,
max: maxy,
autoScale: 'exact',
p2c: function(p) { return p; }
}
};
ctx = setFixtures('<div id="test-container" style="width: 200px;height: 100px;border-style: solid;border-width: 1px"><canvas id="theCanvas" style="width: 100%; height: 100%" /></div>')
.find('#theCanvas')[0]
.getContext('2d');
plotWidth = 200;
plotHeight = 100;
plotOffset = { top: 0, left: 0 };
});
function getPixelColor(ctx, x, y) {
return ctx.getImageData(x, y, 1, 1).data;
}
function rgba(r, g, b, a) {
return [r, g, b, a * 255];
}
it('should draw nothing when the values are null', function () {
series.datapoints.points = [null, null, null, null];
spyOn(ctx, 'moveTo').and.callThrough();
spyOn(ctx, 'lineTo').and.callThrough();
drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
expect(ctx.moveTo).not.toHaveBeenCalled();
expect(ctx.lineTo).not.toHaveBeenCalled();
});
it('should work with NaN, Infinity and -Infinity values', function () {
spyOn(ctx, 'lineTo').and.callThrough();
series.datapoints.points = [Infinity, 0, NaN, NaN, 0, Infinity, 10, -Infinity, -Infinity, 10, 3, 5, 8, 2];
drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
expect(ctx.lineTo).toHaveBeenCalled();
});
it('should draw bars for values', function () {
series.datapoints.points = [0, 0, 150, 25, 50, 75, 200, 100];
spyOn(ctx, 'lineTo').and.callThrough();
drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
expect(ctx.lineTo).toHaveBeenCalled();
});
it('should draw bars using bottom points if provided', function () {
getColorOrGradient = jasmine.createSpy().and.returnValue('rgb(10,200,10)');
series.bars.fill = true;
series.datapoints.points = [0, 10, 0, 1, 10, 1, 2, 10, 2];
series.datapoints.pointsize = 3;
spyOn(ctx, 'fillRect').and.callThrough();
drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
var barHeights = ctx.fillRect.calls.allArgs().map(function (args) {
return args[3];
});
// bottom - top
expect(barHeights).toEqual([-10, -9, -8]);
});
it('should draw bars for fillTowards infinity', function () {
series.datapoints.points = [150, 25];
series.bars.fillTowards = Infinity;
var barWidth = series.bars.barWidth[0] || series.bars.barWidth;
var xaxis = series.xaxis,
yaxis = series.yaxis,
leftValue = xaxis.p2c(series.datapoints.points[0] - barWidth / 2),
rightValue = xaxis.p2c(series.datapoints.points[0] + barWidth / 2),
topValue = yaxis.p2c(maxy),
yValue = xaxis.p2c(series.datapoints.points[1]);
spyOn(ctx, 'lineTo').and.callThrough();
drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
expect(ctx.lineTo.calls.argsFor(0)).toEqual([leftValue, topValue]);
expect(ctx.lineTo.calls.argsFor(1)).toEqual([rightValue, yValue]);
expect(ctx.lineTo.calls.argsFor(2)).toEqual([leftValue, yValue]);
});
it('should draw bars for fillTowards -infinity', function () {
series.datapoints.points = [150, 25];
series.bars.fillTowards = -Infinity;
var barWidth = series.bars.barWidth[0] || series.bars.barWidth;
var xaxis = series.xaxis,
yaxis = series.yaxis,
leftValue = xaxis.p2c(series.datapoints.points[0] - barWidth / 2),
rightValue = xaxis.p2c(series.datapoints.points[0] + barWidth / 2),
bottomValue = yaxis.p2c(miny),
yValue = xaxis.p2c(series.datapoints.points[1]);
spyOn(ctx, 'lineTo').and.callThrough();
drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
expect(ctx.lineTo.calls.argsFor(0)).toEqual([leftValue, yValue]);
expect(ctx.lineTo.calls.argsFor(1)).toEqual([rightValue, yValue]);
expect(ctx.lineTo.calls.argsFor(2)).toEqual([rightValue, bottomValue]);
});
it('should draw bars for fillTowards zero', function () {
series.datapoints.points = [150, 25];
series.bars.fillTowards = 0;
var barWidth = series.bars.barWidth[0] || series.bars.barWidth;
var xaxis = series.xaxis,
yaxis = series.yaxis,
leftValue = xaxis.p2c(series.datapoints.points[0] - barWidth / 2),
rightValue = xaxis.p2c(series.datapoints.points[0] + barWidth / 2),
zeroValue = yaxis.p2c(0),
yValue = xaxis.p2c(series.datapoints.points[1]);
spyOn(ctx, 'lineTo').and.callThrough();
drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, null, getColorOrGradient);
expect(ctx.lineTo.calls.argsFor(0)).toEqual([leftValue, yValue]);
expect(ctx.lineTo.calls.argsFor(1)).toEqual([rightValue, yValue]);
expect(ctx.lineTo.calls.argsFor(2)).toEqual([rightValue, zeroValue]);
});
it('should draw bars with specified color', function () {
var fixture = setFixtures('<div id="demo-container" style="width: 800px;height: 600px">').find('#demo-container').get(0),
placeholder = $('<div id="placeholder" style="width: 100%;height: 100%">');
placeholder.appendTo(fixture);
$.plot(placeholder, [[[45, 25]]], {
series: {
bars: {
lineWidth: 1,
show: true,
fillColor: 'blue'
}
},
xaxis: { autoScale:'exact' }
});
var ctx = $(placeholder).find('.flot-base').get(0).getContext('2d')
insideColor1 = getPixelColor(ctx, ctx.canvas.width / 2, ctx.canvas.height / 2),
insideColor2 = getPixelColor(ctx, ctx.canvas.width / 2 + 35, ctx.canvas.height / 2 - 20),
insideColor3 =getPixelColor(ctx, ctx.canvas.width / 2 - 10, ctx.canvas.height / 2 + 30);
expect(Array.prototype.slice.call(insideColor1)).toEqual(rgba(0,0,255,1));
expect(Array.prototype.slice.call(insideColor2)).toEqual(rgba(0,0,255,1));
expect(Array.prototype.slice.call(insideColor3)).toEqual(rgba(0,0,255,1));
});
it('should use a barWidth based on points distance', function () {
var fixture = setFixtures('<div id="demo-container" style="width: 800px;height: 600px">').find('#demo-container').get(0),
placeholder = $('<div id="placeholder" style="width: 100%;height: 100%">');
placeholder.appendTo(fixture);
var testVector = [[[[[0.1, 1], [0.2, 10]]], 0.08],
[[[[1, 1], [2, 10]]], 0.8],
[[[[10, 1], [20, 10]]], 8],
[[[[1000, 1], [2000, 10], [2100, 10]]], 80],
[[[]], 0.8],
[[[[-5, 1], [30, 15], [20, 7], [5, 2]]], 8]],
plot;
for (var i = 0; i< testVector.length; i++) {
plot = $.plot(placeholder, testVector[i][0], {
series: {
bars: {
lineWidth: 1,
show: true,
}
},
});
var barWidth = plot.getData()[0].bars.barWidth[0] || plot.getData()[0].bars.barWidth;
expect(barWidth).toBeCloseTo(testVector[i][1], 4);
}
});
it('should be able to compute barWidth for NaN, Infinity and -Infinity values', function () {
var fixture = setFixtures('<div id="test-container" style="width: 600px;height: 400px"><canvas id="theCanvas" style="width: 100%; height: 100%" /></div>'),
placeholder = fixture.find('#test-container');
placeholder.appendTo(fixture);
var plot = $.plot(placeholder, [[[Infinity, 0], [0, Infinity], [10, -Infinity], [-Infinity, 10], [3, 5], [8, 2], [NaN, NaN]]], {series: series});
var axes = plot.getAxes();
var barWidth = plot.getData()[0].bars.barWidth[0] || plot.getData()[0].bars.barWidth;
expect(barWidth).toEqual(4);
});
});
});

View File

@@ -0,0 +1,151 @@
/* eslint-disable */
describe("unit tests for the precision of axis", function() {
var plot;
var placeholder;
var sampledata = [[0, 1], [1, 1.1], [2, 1.2]];
beforeEach(function () {
var fixture = setFixtures('<div id="demo-container" style="width: 800px;height: 600px">').find('#demo-container').get(0);
placeholder = $('<div id="placeholder" style="width: 100%;height: 100%">');
placeholder.appendTo(fixture);
});
afterEach(function () {
if (plot) {
plot.shutdown();
}
$('#placeholder').empty();
});
it('should use the precision given by tickDecimals when specified', function() {
plot = $.plot("#placeholder", [sampledata], {});
var testVector = [
[1, 10, 10, 3, 1],
[1, 1.01, 10, 2, 2],
[0.99963, 0.99964, null, 3, 3],
[1, 1.1, 5, 1, 1],
[1, 1.00000000000001, 10, 5, 5]
];
testVector.forEach(function (t) {
var min = t[0],
max = t[1],
ticks = t[2],
tickDecimals = t[3],
expectedValue = t[4];
var precision = plot.computeValuePrecision(min, max, "x", ticks, tickDecimals);
expect(precision).toEqual(expectedValue);
});
});
it('should use the maximum precision when tickDecimals not specified', function() {
plot = $.plot("#placeholder", [sampledata], {});
var testVector = [
[1, 10, 10, 1],
[1, 1.01, 10, 3],
[1, 1.1, 5, 2],
[0.99963, 0.99964, null, 6],
[1, 1.00000000000001, 10, 16],
[-200000, 200000, undefined, -4]
];
testVector.forEach(function (t) {
var min = t[0],
max = t[1],
ticks = t[2],
expectedValue = t[3];
var precision = plot.computeValuePrecision(min, max, "x", ticks);
expect(precision).toEqual(expectedValue);
});
});
it('should increase precision for endpoints', function() {
var testVector = [
[1, 10, 10, 'linear', '1.00', '10.00'],
[1, 100, 11, 'linear', '1.0', '100.0'],
[-1, 1, 20, 'linear', '-1.000', '1.000'],
[1, 1.01, 10, 'linear', '1.00000', '1.01000'],
[99, 99.02, 10, 'linear', '99.00000', '99.02000'],
[0.99963, 0.99964, null, 'linear', '0.99963000', '0.99964000'],
[1, 1.00000000001, 100, 'linear', '1.00000000000000', '1.00000000001000'],
[-2000000, 2000000, null, 'linear', '-2000000', '2000000'],
[-2.18167311226e+21, 2.196693453e+21, null, 'linear', '-2.182e21', '2.197e21'],
[1, 10, 10, 'log', '1.000', '10.00'],
[1, 10000000, 10, 'log', '1.00', '10000000'],
[0.1, 100, 11, 'log', '0.1000', '100.0'],
[0.99963, 0.99964, null, 'log', '0.99963000', '0.99964000'],
[1, 2000000, null, 'log', '1.00', '2000000'],
[1.14567e-43, 1, null, 'log', '1.1e-43', '1.0'],
[0, 1, null, 'log', '0.1000', '1.000']
];
testVector.forEach(function (t) {
plot = $.plot("#placeholder", [sampledata], {
xaxes: [{
min: t[0],
max: t[1],
ticks: t[2],
showTickLabels : 'endpoints',
autoScale: "none",
mode: t[3]
}]
});
var minExpectedValue = t[4],
maxExpectedValue = t[5],
xaxis = plot.getAxes().xaxis;
expect(xaxis.ticks[0].label).toEqual(minExpectedValue);
expect(xaxis.ticks[xaxis.ticks.length-1].label).toEqual(maxExpectedValue);
});
});
describe('tickFormatter', function(){
it('should ignore the computed precision of axis if negative', function(){
var testVector = [[-12356285.9999, -10, '-12356286'],
[12356285.9999, -10, '12356286'],
[3.215, -1, '3'],
[3.215, -2, '3'],
[3.215, -3, '3'],
[3.215, -50, '3']];
testVector.forEach(function (t) {
plot = $.plot("#placeholder", [], {
xaxes: [{
showTickLabels : 'all',
}]
});
var axis = plot.getXAxes()[0];
expect($.plot.defaultTickFormatter(t[0], axis, t[1])).toEqual(t[2]);
});
});
it('should show small number of decimals for numbers with e representation', function(){
var testVector = [[0.12e-8, 1.2e-7, '1.2e-9', '1.200e-7'],
[1.2e+21, 12e+21, '1.20e21', '1.200e22'],
[1e-18, 2e-18, '1.000e-18', '2.000e-18'],
[1.000000001e-18, 1.99999999e-18, '1.000e-18', '2.000e-18'],
[0.000000000000001, 0.0000000000002, '1.0e-15', '2.000e-13']];
testVector.forEach(function (t) {
plot = $.plot("#placeholder", [sampledata], {
xaxes: [{
showTickLabels : 'endpoints',
min : t[0],
max : t[1],
autoScale : 'none'
}]
});
var axis = plot.getXAxes()[0];
expect(axis.ticks[0].label).toEqual(t[2]);
expect(axis.ticks[axis.ticks.length - 1].label).toEqual(t[3]);
});
});
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,143 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe('flot axis labels plugin', function() {
var placeholder, plot;
var options;
beforeEach(function() {
options = {
xaxes: [
{ position: 'bottom', axisLabel: 'Bottom 1' },
{ position: 'top', axisLabel: 'Bottom 2', show: true },
],
yaxes: [
{ position: 'left', axisLabel: 'Left' },
{ position: 'right', axisLabel: 'Right', show: true }
]
};
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px">')
.find('#test-container');
});
it('creates a html text node for each axis label', function () {
plot = $.plot(placeholder, [[]], options);
var labels$ = $('.axisLabels'),
labels = labels$.map(function(i, label) {
return label.textContent;
}).get();
expect(labels.length).toBe(4);
expect(labels).toContain(options.xaxes[0].axisLabel);
expect(labels).toContain(options.xaxes[1].axisLabel);
expect(labels).toContain(options.yaxes[0].axisLabel);
expect(labels).toContain(options.yaxes[1].axisLabel);
});
it('doesn`t create a html text node for each axis label when the plugin is disabled', function () {
options.axisLabels = {
show: false
};
plot = $.plot(placeholder, [[]], options);
var labels$ = $('.axisLabels'),
labels = labels$.map(function(i, label) {
return label.innerText;
}).get();
expect(labels.length).toBe(0);
});
it('shrinks the drawing area to make space for the axis labels', function () {
plot = $.plot(placeholder, [[]], options);
var width = plot.width(),
height = plot.height();
options.axisLabels = {
show: false
};
plot = $.plot(placeholder, [[]], options);
var widthNoLabels = plot.width(),
heightNoLabels = plot.height();
expect(widthNoLabels).toBeGreaterThan(width);
expect(heightNoLabels).toBeGreaterThan(height);
});
it('centers the labels of x axes horizontally', function () {
options.xaxes[0].axisLabel = 'short label';
options.xaxes[1].axisLabel = 'very long axis label';
plot = $.plot(placeholder, [[]], options);
var box1 = $('.x1Label')[0].getBoundingClientRect(),
box2 = $('.x2Label')[0].getBoundingClientRect();
expect((box1.left + box1.width / 2) - (box2.left + box2.width / 2)).toBeLessThan(2);
});
it('centers the labels of y axes vertically', function () {
options.yaxes[0].axisLabel = 'short label';
options.yaxes[1].axisLabel = 'very long axis label';
plot = $.plot(placeholder, [[]], options);
var box1 = $('.y1Label')[0].getBoundingClientRect(),
box2 = $('.y2Label')[0].getBoundingClientRect(),
c1 = box1.top + box1.height / 2,
c2 = box2.top + box2.height / 2;
// The error on the y axes can be up to 1px because of the rotation
expect(Math.abs(c1 - c2)).toBeLessThan(2);
});
it('should not duplicate the labels when the data is redrawn', function () {
plot = $.plot(placeholder, [[1, 2, 3]], options);
var labels$ = $('.axisLabels');
expect(labels$.length).toBe(4);
plot.setData([[4, 5, 6]]);
plot.setupGrid();
plot.draw();
labels$ = $('.axisLabels');
expect(labels$.length).toBe(4);
});
it('should not duplicate the labels when the plot is recreated', function () {
plot = $.plot(placeholder, [[1, 2, 3]], options);
var labels$ = $('.axisLabels');
expect(labels$.length).toBe(4);
plot = $.plot(placeholder, [[1, 2, 3]], options);
labels$ = $('.axisLabels');
expect(labels$.length).toBe(4);
});
it('should reserve extra space when axis.boxPosition is specified', function () {
var size = 20,
options = {
xaxes: [
{ position: 'bottom', axisLabel: 'Bottom 1', boxPosition: {centerX: size, centerY: size} },
{ position: 'bottom', axisLabel: 'Bottom 2', show: true }
]
};
plot = $.plot(placeholder, [[1, 2, 3]], options);
var axes = plot.getXAxes();
expect(axes[0].labelHeight).toBe(axes[1].labelHeight + size);
expect(axes[0].labelWidth).toBe(axes[1].labelWidth + size);
});
it('should reserve the specified space by axis.boxPosition even if axisLabel not visible', function () {
var size = 20,
options = {
yaxes: [
{ position: 'right', boxPosition: {centerX: size, centerY: size} },
{ position: 'right', show: true }
]
};
plot = $.plot(placeholder, [[1, 2, 3]], options);
var axes = plot.getYAxes();
expect(axes[0].labelHeight).toBe(axes[1].labelHeight + size);
expect(axes[0].labelWidth).toBe(axes[1].labelWidth + size);
});
});

View File

@@ -0,0 +1,332 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe('CanvasWrapper', function() {
var placeholder;
beforeEach(function() {
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px">')
.find('#test-container');
});
it('should create a new canvas element', function() {
var canvas = new Flot.Canvas('myCanvas', placeholder[0]);
expect(canvas.element).toBeTruthy();
expect(placeholder.find('.myCanvas')).toBeTruthy();
});
it('should reuse an existing canvas with the same class', function() {
var canvas1 = new Flot.Canvas('myCanvas', placeholder[0]);
var element1 = placeholder.find('.myCanvas')[0];
var canvas2 = new Flot.Canvas('myCanvas', placeholder[0]);
var element2 = placeholder.find('.myCanvas')[0];
expect(element1).toBe(element2);
expect(placeholder.find('.myCanvas').length).toBe(1);
});
it('should resize the canvas to the given width and height', function() {
var canvas = newCanvas(placeholder);
canvas.resize(222, 333);
expect(canvas.width).toBe(222);
expect(canvas.height).toBe(333);
expect(canvas.element.style.width).toBe('222px');
expect(canvas.element.style.height).toBe('333px');
});
it('should resize the canvas but not less than a minimum width and height', function() {
var canvas = newCanvas(placeholder);
canvas.resize(0, 0);
expect(canvas.width).toBe(10);
expect(canvas.height).toBe(10);
expect(canvas.element.style.width).toBe('10px');
expect(canvas.element.style.height).toBe('10px');
});
it('should measure the width and height of a text', function() {
var canvas = newCanvas(placeholder);
var info = canvas.getTextInfo('', 'text');
expect(info.width).toBeGreaterThan(0);
expect(info.height).toBeGreaterThan(0);
});
it('should measure the width and height of a text based on its own CSS', function() {
var canvas = newCanvas(placeholder);
appendSetStyleFixtures('.a { font-size: 10px; }');
appendSetStyleFixtures('.b { font-size: 20px; }');
var info1 = canvas.getTextInfo('', 'text', 'a');
var info2 = canvas.getTextInfo('', 'text', 'b');
expect(info2.width).toBeGreaterThan(info1.width);
expect(info2.height).toBeGreaterThan(info1.height);
});
it('should measure the width and height of a text based on its layer CSS', function() {
var canvas = newCanvas(placeholder);
appendSetStyleFixtures('.a { font-size: 10px; }');
appendSetStyleFixtures('.b { font-size: 20px; }');
var info1 = canvas.getTextInfo('a', 'text');
var info2 = canvas.getTextInfo('b', 'text');
expect(info2.width).toBeGreaterThan(info1.width);
expect(info2.height).toBeGreaterThan(info1.height);
});
it('should measure the width of a text based on its actual length', function() {
var canvas = newCanvas(placeholder);
appendSetStyleFixtures('.a { font-size: 10px; }');
var info1 = canvas.getTextInfo('a', 'text');
var info2 = canvas.getTextInfo('a', 'longer text');
expect(info2.width).toBeGreaterThan(info1.width);
});
it('should return the same width and height for numbers with the same digit count', function() {
var canvas = newCanvas(placeholder);
var info1 = canvas.getTextInfo('', '01234');
var info2 = canvas.getTextInfo('', '56789');
expect(info2.width).toBe(info1.width);
});
it('should add text at the given layer, coords, and font CSS', function() {
var canvas = newCanvas(placeholder);
canvas.addText('layer', 100, 200, '123', 'a');
canvas.render();
var elem = placeholder.find('.a')[0],
box = elem.getBoundingClientRect();
//TODO Raluca: This should be fixed. Given the starting position for drawing SVG text element, there is a difference between HTML and SVG element placement.
//expect(box.left).toBe(100);
//expect(box.top).toBe(200);
expect(elem.className.baseVal).toBe('a');
expect(elem.parentNode.className.baseVal).toBe('layer');
});
it('should add the same text with the same CSS at different coords', function() {
var canvas = newCanvas(placeholder);
canvas.addText('layerA', 100, 200, '123', 'a');
canvas.addText('layerA', 300, 400, '123', 'a');
canvas.render();
var elem1 = placeholder.find('.a')[0],
elem2 = placeholder.find('.a')[1],
box1 = elem1.getBoundingClientRect(),
box2 = elem2.getBoundingClientRect();
expect(elem2.textContent).toBe(elem2.textContent);
expect(box2.left).not.toBe(box1.left);
expect(box2.top).not.toBe(box1.top);
});
it('should add different text with the same CSS at different coords', function() {
var canvas = newCanvas(placeholder);
canvas.addText('layerA', 100, 200, '123', 'a');
canvas.addText('layerA', 300, 400, '456', 'a');
canvas.render();
var elem1 = placeholder.find('.a')[0],
elem2 = placeholder.find('.a')[1],
box1 = elem1.getBoundingClientRect(),
box2 = elem2.getBoundingClientRect();
expect(elem2.textContent).not.toBe(elem1.textContent);
expect(box2.left).not.toBe(box1.left);
expect(box2.top).not.toBe(box1.top);
});
it('should add different text with the same CSS and the same coords', function() {
var canvas = newCanvas(placeholder);
canvas.addText('layerA', 100, 200, '123', 'a');
canvas.addText('layerA', 100, 200, '456', 'a');
canvas.addText('layerA', 100, 200, '7890', 'a');
canvas.render();
var elems = placeholder.find('.a');
expect(elems.length).toBe(3);
});
it('should add multiple tspan for text that contains br tag', function() {
var canvas = newCanvas(placeholder);
canvas.addText('layerA', 100, 200, '1<br>2<br>3<br>4', 'a');
canvas.render();
var elem = placeholder.find('.a')[0];
expect(elem.childNodes.length).toBe(4);
});
it('should update the tspan element content', function() {
var canvas = newCanvas(placeholder);
canvas.addText('layerA', 100, 200, '1<br>2<br>3', 'a');
canvas.render();
canvas.removeText('layerA', 100, 200, '1<br>2<br>3', 'a');
canvas.addText('layerA', 130, 230, '1<br>2<br>3<br>4', 'a');
canvas.render();
var elem = placeholder.find('.a')[0];
expect(elem.childNodes.length).toBe(4);
});
it('should update the cache position of the elements', function() {
var canvas = newCanvas(placeholder);
canvas.addText('layerA', 100, 200, '123', 'a');
canvas.render();
canvas.removeText('layerA', 100, 200, '123', 'a');
canvas.addText('layerA', 130, 230, '123', 'a');
canvas.render();
canvas.addText('layerA', 100, 200, '123', 'a');
canvas.render();
var elems = placeholder.find('.a');
expect(elems.length).toBe(2);
});
it('should not add the same text with the same CSS and the same coords twice', function() {
var canvas = newCanvas(placeholder);
canvas.addText('layerA', 100, 200, '123', 'a');
canvas.addText('layerA', 100, 200, '123', 'a');
canvas.render();
var elems = placeholder.find('.a');
expect(elems.length).toBe(1);
});
it('should remove all text from a given layer', function() {
var canvas = newCanvas(placeholder);
canvas.addText('layerA', 100, 200, '123', 'a');
canvas.addText('layerA', 300, 400, '123', 'a');
canvas.addText('layerA', 500, 600, '456', 'b');
canvas.addText('layerA', 700, 800, '456', 'b');
canvas.addText('layerB', 200, 100, '123', 'c');
canvas.addText('layerB', 400, 300, '456', 'c');
canvas.render();
canvas.removeText('layerA', NaN, NaN, null);
canvas.render();
var as = placeholder.find('.a'),
bs = placeholder.find('.b'),
cs = placeholder.find('.c');
expect(as.length).toBe(0);
expect(bs.length).toBe(0);
expect(cs.length).toBe(2);
});
it('should remove specific text from specific layer and coords', function() {
var canvas = newCanvas(placeholder);
canvas.addText('layerA', 100, 200, '123', 'a');
canvas.addText('layerA', 300, 400, '123', 'a');
canvas.addText('layerA', 500, 600, '123', 'b');
canvas.addText('layerA', 700, 800, '123', 'b');
canvas.addText('layerB', 200, 100, '123', 'c');
canvas.addText('layerB', 400, 300, '123', 'c');
canvas.render();
canvas.removeText('layerA', 300, 400, '123', 'a');
canvas.render();
var as = placeholder.find('.a'),
bs = placeholder.find('.b'),
cs = placeholder.find('.c');
expect(as.length).toBe(1);
expect(bs.length).toBe(2);
expect(cs.length).toBe(2);
});
it('should remove specific text from specific layer and coords when more texts overlaps', function() {
var canvas = newCanvas(placeholder);
canvas.addText('layerA', 100, 200, '123', 'a');
canvas.addText('layerA', 100, 200, '456', 'a');
canvas.addText('layerA', 100, 200, '7890', 'a');
canvas.render();
var initialTextElements = placeholder.find('.a');
expect(initialTextElements.length).toBe(3);
canvas.removeText('layerA', 100, 200, '456', 'a');
canvas.render();
var finalTextElements = placeholder.find('.a');
expect(finalTextElements.length).toBe(2);
var remainingTexts = [finalTextElements[0].textContent, finalTextElements[1].textContent];
expect(remainingTexts).toContain('123');
expect(remainingTexts).toContain('7890');
});
it('should remove all text', function() {
var canvas = newCanvas(placeholder);
canvas.addText('layerA', 100, 200, '123', 'a');
canvas.addText('layerA', 300, 400, '456', 'b');
canvas.addText('layerB', 500, 600, '789', 'c');
canvas.render();
canvas.clearCache();
var as = placeholder.find('.a'),
bs = placeholder.find('.b'),
cs = placeholder.find('.c');
expect(as.length).toBe(0);
expect(bs.length).toBe(0);
expect(cs.length).toBe(0);
});
it('should move&replace obsolete text', function() {
var canvas = newCanvas(placeholder);
canvas.addText('layerA', 100, 200, '123', 'a');
canvas.render();
var elem = placeholder.find('.a')[0];
elem._marker = '_marker';
canvas.removeText('layerA', NaN, NaN, null);
canvas.addText('layerA', 300, 400, '456', 'a');
canvas.render();
elem = placeholder.find('.a')[0];
expect(elem._marker).toBe('_marker');
});
it('should work with an object instead of a class name', function() {
var canvas = newCanvas(placeholder)
settings = {
style: 'normal',
variant: 'normal',
weight: '400',
size: '40',
lineHeight: '23',
family: '"Times New Roman"',
fill: 'rgb(100, 200, 0)'
};
var info = canvas.getTextInfo('layerA', '123', settings);
expect(info.width).toBeGreaterThan(10);
canvas.addText('layerA', 100, 200, '123', settings);
canvas.render();
var as = placeholder.find('.layerA'),
style = window.getComputedStyle(as[0].firstChild),
layerAColor = $.color.parse(style.fill),
styleColor = $.color.parse(settings.fill);
expect(as.length).toBe(1);
expect(style.fontFamily).toContain(settings.family.slice(1, -1));
expect(layerAColor.toString()).toBe(styleColor.toString());
canvas.removeText('layerA', 100, 200, '123', settings);
canvas.render();
as = placeholder.find('.a');
expect(as.length).toBe(0);
});
function newCanvas(placeholder) {
return new Flot.Canvas('myCanvas', placeholder[0]);
}
});

View File

@@ -0,0 +1,107 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe("colorhelpers plugin", function() {
it('can make a new color', function () {
var color = $.color.make(10, 20, 30, 0.5);
expect(color.r).toBe(10);
expect(color.g).toBe(20);
expect(color.b).toBe(30);
expect(color.a).toBe(0.5);
});
it('scales the specified components with given factor', function () {
var color = $.color.make(10, 20, 30, 0.5);
var factor = 0.2;
color.scale('ga', factor);
expect(color.r).toBe(10);
expect(color.g).toBe(20 * factor);
expect(color.b).toBe(30);
expect(color.a).toBe(0.5 * factor);
});
it('adds to the specified component a given delta', function () {
var color = $.color.make(10, 20, 30, 0.5);
var delta = 3;
color.add('rb', delta);
expect(color.r).toBe(10 + delta);
expect(color.g).toBe(20);
expect(color.b).toBe(30 + delta);
expect(color.a).toBe(0.5);
});
it('normalizes the invalid values', function () {
var color = $.color.make(-1, 256, 200.1, -0.1);
expect(color.r).toBe(0);
expect(color.g).toBe(255);
expect(color.b).toBe(200);
expect(color.a).toBe(0);
});
it('normalizes the invalid values', function () {
var color = $.color.make(-1, 256, 200.1, -0.1);
expect(color.r).toBe(0);
expect(color.g).toBe(255);
expect(color.b).toBe(200);
expect(color.a).toBe(0);
});
it('can make a new color object based on different color format string', function() {
[
'rgb(17, 170, 187)',
'rgba(17, 170, 187, 1)',
'#1ab',
'#11aabb'
].forEach(function(str) {
color = $.color.parse(str);
expect(color.r).toBe(17);
expect(color.g).toBe(170);
expect(color.b).toBe(187);
expect(color.a).toBe(1);
});
});
it('can make a new color object based on a named color string', function() {
[
{ str: 'darkolivegreen', rgba: [85, 107, 47, 1] },
{ str: 'transparent', rgba: [255, 255, 255, 0] }
].forEach(function(tc) {
color = $.color.parse(tc.str);
expect(color.r).toBe(tc.rgba[0]);
expect(color.g).toBe(tc.rgba[1]);
expect(color.b).toBe(tc.rgba[2]);
expect(color.a).toBe(tc.rgba[3]);
});
});
describe('by looking in DOM', function() {
var testElement;
beforeEach(function() {
testElement = setFixtures('<div style="color: red"><div id="test-element" style="background-color: yellow" /></div>')
.find('#test-element');
});
it('extracts a specified CSS color from a given element', function() {
var color = $.color.extract(testElement, 'background-color');
expect($.color.parse('yellow').toString()).toBe(color.toString());
});
it('extracts a specified CSS color from the parent of a given element', function() {
var color = $.color.extract(testElement, 'color');
expect($.color.parse('red').toString()).toBe(color.toString());
});
});
});

View File

@@ -0,0 +1,768 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe("composeImages", function() {
var placeholder, plot;
var composeImages = $.plot.composeImages,
canvasData = window.colors.canvasData;
beforeEach(function() {
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px; padding: 0px margin: 0px; border: 0px; font-size:0pt; font-family:sans-serif; line-height:0px;">')
.find('#test-container');
jasmine.addMatchers(window.colors.jasmineMatchers);
});
it('should call composeImages on an empty array of sources, so the destination canvas should stay unmodified', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'</div>' +
'<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('svg').toArray();
var destinationCanvas = document.getElementById("myCanvas");
function drawCircleOnToCanvas(canvas) {
var ctx = canvas.getContext('2d');
ctx.arc(80, 10, 5, 0, 2 * Math.PI);
ctx.fill();
}
drawCircleOnToCanvas(destinationCanvas); //make sure composeImages won't modify this content
composeImages(sources, destinationCanvas).then(function() {
expect(canvasData(destinationCanvas, 80, 10, 1, 1)).toMatchPixelColor([0, 0, 0, 255]);
expect(destinationCanvas.width).toBe(300);
expect(destinationCanvas.height).toBe(150);
expect(canvasData(destinationCanvas, 10, 10, 1, 1)).toMatchPixelColor([0, 0, 0, 0]);
expect(canvasData(destinationCanvas, 30, 40, 1, 1)).toMatchPixelColor([0, 0, 0, 0]);
expect(canvasData(destinationCanvas, 50, 70, 1, 1)).toMatchPixelColor([0, 0, 0, 0]);
expect(canvasData(destinationCanvas, 10, 110, 1, 1)).toMatchPixelColor([0, 0, 0, 0]);
expect(canvasData(destinationCanvas, 30, 140, 1, 1)).toMatchPixelColor([0, 0, 0, 0]);
expect(canvasData(destinationCanvas, 50, 170, 1, 1)).toMatchPixelColor([0, 0, 0, 0]);
done();
}, null);
});
it('should call composeImages on one SVG as a source', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<svg id="svgSource" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" width="100" height="100" title="svg">' +
'<circle id="c1" cx="10" cy="10" r="5" style="fill:red"/>' +
'<circle id="c2" cx="30" cy="40" r="7" style="fill:#00FF00"/>' +
'<circle id="c3" cx="50" cy="70" r="9" style="fill:blue"/>' +
'</svg>' +
'</div>' +
'<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('svg').toArray();
var destinationCanvas = document.getElementById("myCanvas");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(100);
expect(destinationCanvas.height).toBe(100);
expect(canvasData(destinationCanvas, 10, 10, 1, 1)).toMatchPixelColor([255, 0, 0, 255]);
expect(canvasData(destinationCanvas, 30, 40, 1, 1)).toMatchPixelColor([0, 255, 0, 255]);
expect(canvasData(destinationCanvas, 50, 70, 1, 1)).toMatchPixelColor([0, 0, 255, 255]);
done();
}, null);
});
it('should call composeImages on two identical SVGs, one near the other', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<svg id="svgSource" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" width="100" height="100" title="svg">' +
'<circle id="c1" cx="10" cy="10" r="5" style="fill:red"/>' +
'<circle id="c2" cx="30" cy="40" r="7" style="fill:#00FF00"/>' +
'<circle id="c3" cx="50" cy="70" r="9" style="fill:blue"/>' +
'</svg>' +
'<svg id="svgSource2" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" width="100" height="100" title="svg2">' +
'<circle id="c1" cx="10" cy="10" r="5" style="fill:red"/>' +
'<circle id="c2" cx="30" cy="40" r="7" style="fill:#00FF00"/>' +
'<circle id="c3" cx="50" cy="70" r="9" style="fill:blue"/>' +
'</svg>' +
'</div>' +
'<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('svg').toArray();
var destinationCanvas = document.getElementById("myCanvas");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(200); //204 - //200 + 2 * 2px_spacing
expect(destinationCanvas.height).toBe(100);
expect(canvasData(destinationCanvas, 10, 10, 1, 1)).toMatchPixelColor([255, 0, 0, 255]);
expect(canvasData(destinationCanvas, 30, 40, 1, 1)).toMatchPixelColor([0, 255, 0, 255]);
expect(canvasData(destinationCanvas, 50, 70, 1, 1)).toMatchPixelColor([0, 0, 255, 255]);
expect(canvasData(destinationCanvas, 110, 10, 1, 1)).toMatchPixelColor([255, 0, 0, 255]); //110 + 4
expect(canvasData(destinationCanvas, 130, 40, 1, 1)).toMatchPixelColor([0, 255, 0, 255]); //130 + 4
expect(canvasData(destinationCanvas, 150, 70, 1, 1)).toMatchPixelColor([0, 0, 255, 255]); //150 + 4
done();
}, null);
});
it('should call composeImages on two identical SVGs, one after the other', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<svg id="svgSource" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" width="100" height="100" title="svg">' +
'<circle id="c1" cx="10" cy="10" r="5" style="fill:#FF0000"/>' +
'<circle id="c2" cx="30" cy="40" r="7" style="fill:#00FF00"/>' +
'<circle id="c3" cx="50" cy="70" r="9" style="fill:#0000FF"/>' +
'</svg>' +
'<br>' +
'<svg id="svgSource2" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" width="100" height="100" title="svg2">' +
'<circle id="c1" cx="10" cy="10" r="5" style="fill:#FF0000"/>' +
'<circle id="c2" cx="30" cy="40" r="7" style="fill:#00FF00"/>' +
'<circle id="c3" cx="50" cy="70" r="9" style="fill:#0000FF"/>' +
'</svg>' +
'</div>' +
'<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('svg').toArray();
var destinationCanvas = document.getElementById("myCanvas");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(100);
expect(destinationCanvas.height).toBe(200); //204 - //200 + 2 * 2px_spacing
expect(canvasData(destinationCanvas, 10, 10, 1, 1)).toMatchPixelColor([255, 0, 0, 255]);
expect(canvasData(destinationCanvas, 30, 40, 1, 1)).toMatchPixelColor([0, 255, 0, 255]);
expect(canvasData(destinationCanvas, 50, 70, 1, 1)).toMatchPixelColor([0, 0, 255, 255]);
expect(canvasData(destinationCanvas, 10, 110, 1, 1)).toMatchPixelColor([255, 0, 0, 255]); //110 + 4
expect(canvasData(destinationCanvas, 30, 140, 1, 1)).toMatchPixelColor([0, 255, 0, 255]); //140 + 4
expect(canvasData(destinationCanvas, 50, 170, 1, 1)).toMatchPixelColor([0, 0, 255, 255]); //170 + 4
done();
}, null);
});
it('should call composeImages on three identical SVGs, placed in an L-shape', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<svg id="svgSource1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" width="100" height="100" title="svg1">' +
'<circle id="c1" cx="10" cy="10" r="5" style="fill:red"/>' +
'<circle id="c2" cx="30" cy="40" r="7" style="fill:#00FF00"/>' +
'<circle id="c3" cx="50" cy="70" r="9" style="fill:blue"/>' +
'</svg>' +
'<svg id="svgSource2" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" width="100" height="100" title="svg2">' +
'<circle id="c1" cx="10" cy="10" r="5" style="fill:red"/>' +
'<circle id="c2" cx="30" cy="40" r="7" style="fill:#00FF00"/>' +
'<circle id="c3" cx="50" cy="70" r="9" style="fill:blue"/>' +
'</svg>' +
'<br>' +
'<svg id="svgSource3" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" width="100" height="100" title="svg3">' +
'<circle id="c1" cx="10" cy="10" r="5" style="fill:red"/>' +
'<circle id="c2" cx="30" cy="40" r="7" style="fill:#00FF00"/>' +
'<circle id="c3" cx="50" cy="70" r="9" style="fill:blue"/>' +
'</svg>' +
'</div>' +
'<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('svg').toArray();
var destinationCanvas = document.getElementById("myCanvas");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(200); //204 - //200 + 2 * 2px_spacing
expect(destinationCanvas.height).toBe(200); //204 - //200 + 2 * 2px_spacing
expect(canvasData(destinationCanvas, 10, 10, 1, 1)).toMatchPixelColor([255, 0, 0, 255]);
expect(canvasData(destinationCanvas, 30, 40, 1, 1)).toMatchPixelColor([0, 255, 0, 255]);
expect(canvasData(destinationCanvas, 50, 70, 1, 1)).toMatchPixelColor([0, 0, 255, 255]);
expect(canvasData(destinationCanvas, 110, 10, 1, 1)).toMatchPixelColor([255, 0, 0, 255]); //110 + 4
expect(canvasData(destinationCanvas, 130, 40, 1, 1)).toMatchPixelColor([0, 255, 0, 255]); //130 + 4
expect(canvasData(destinationCanvas, 150, 70, 1, 1)).toMatchPixelColor([0, 0, 255, 255]); //150 + 4
expect(canvasData(destinationCanvas, 10, 110, 1, 1)).toMatchPixelColor([255, 0, 0, 255]); //110 + 4
expect(canvasData(destinationCanvas, 30, 140, 1, 1)).toMatchPixelColor([0, 255, 0, 255]); //140 + 4
expect(canvasData(destinationCanvas, 50, 170, 1, 1)).toMatchPixelColor([0, 0, 255, 255]); //170 + 4
done();
}, null);
});
it('should call composeImages on one canvas as a source', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<canvas id="canvasSource" width="20" height="20" title="canvasSource"></canvas>' +
'</div>' +
'<canvas id="myCanvas" width="30" height="15" style="border:1px solid #d3d3d3;"></canvas>'
).find('#canvasSource').toArray();
var originalCanvas = document.getElementById("canvasSource");
var destinationCanvas = document.getElementById("myCanvas");
drawSomeLinesOnCanvas(originalCanvas);
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(20);
expect(destinationCanvas.height).toBe(20);
expect(canvasData(originalCanvas, 0, 0, 20, 20))
.toMatchCanvasArea(canvasData(destinationCanvas, 0, 0, 20, 20));
done();
}, null);
});
it('should call composeImages on one canvas and one SVG', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<canvas class="imgsrc" id="canvasSource" width="20" height="20" title="canvasSource"></canvas>' +
'<svg class="imgsrc" id="svgSource1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" width="100" height="100" title="svg1">' +
'<circle id="c1" cx="10" cy="10" r="5" style="fill:red"/>' +
'<circle id="c2" cx="30" cy="40" r="7" style="fill:#00FF00"/>' +
'<circle id="c3" cx="50" cy="70" r="9" style="fill:blue"/>' +
'</svg>' +
'</div>' +
'<canvas id="myCanvas" width="30" height="15" style="border:1px solid #d3d3d3;"></canvas>'
).find('.imgsrc').toArray();
var originalCanvas = document.getElementById("canvasSource");
var destinationCanvas = document.getElementById("myCanvas");
drawSomeLinesOnCanvas(originalCanvas);
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(120); //124 - //120 + 2 * 2px_spacing
expect(destinationCanvas.height).toBe(100);
expect(canvasData(originalCanvas, 0, 0, 20, 20))
.toMatchCanvasArea(canvasData(destinationCanvas, 0, 80, 20, 20));
expect(canvasData(destinationCanvas, 20 + 10, 10, 1, 1)).toMatchPixelColor([255, 0, 0, 255]); //24 + 10
expect(canvasData(destinationCanvas, 20 + 30, 40, 1, 1)).toMatchPixelColor([0, 255, 0, 255]); //24 + 30
expect(canvasData(destinationCanvas, 20 + 50, 70, 1, 1)).toMatchPixelColor([0, 0, 255, 255]); //24 + 50
done();
}, null);
});
it('should call composeImages on two canvases', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<canvas class="imgsrc" id="canvasSource1" width="20" height="20" title="canvasSource1"></canvas>' +
'<canvas class="imgsrc" id="canvasSource2" width="20" height="20" title="canvasSource2"></canvas>' +
'</div>' +
'<canvas id="myCanvas" width="30" height="15" style="border:1px solid #d3d3d3;"></canvas>'
).find('.imgsrc').toArray();
var originalCanvas1 = document.getElementById("canvasSource1");
var originalCanvas2 = document.getElementById("canvasSource2");
var destinationCanvas = document.getElementById("myCanvas");
drawARectangleOnCanvas(originalCanvas1, "#FF0000");
drawARectangleOnCanvas(originalCanvas2, "#00FF00");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(40); //44 - //2 * 20 + 2 * spacing
expect(destinationCanvas.height).toBe(20);
expect(canvasData(originalCanvas1, 0, 0, 20, 20))
.toMatchCanvasArea(canvasData(destinationCanvas, 0, 0, 20, 20));
expect(canvasData(originalCanvas2, 0, 0, 20, 20))
.toMatchCanvasArea(canvasData(destinationCanvas, 20 + 0, 0, 20, 20)); //20 + 4
done();
}, null);
});
it('should call composeImages on two partially overlapped canvases', function (done) {
var sources = placeholder.html('<style type="text/css">' +
'#canvasSource2 {position:relative; left:-10px;}' +
'</style>' +
'<div id="test-container" style="width: 600px;height: 400px">' +
'<canvas class="imgsrc" id="canvasSource1" width="20" height="20" title="canvasSource1"></canvas>' +
'<canvas class="imgsrc" id="canvasSource2" width="20" height="20" title="canvasSource2"></canvas>' +
'</div>' +
'<canvas id="myCanvas" width="30" height="15" style="border:1px solid #d3d3d3;"></canvas>'
).find('.imgsrc').toArray();
var originalCanvas1 = document.getElementById("canvasSource1");
var originalCanvas2 = document.getElementById("canvasSource2");
var destinationCanvas = document.getElementById("myCanvas");
drawARectangleOnCanvas(originalCanvas1, "#FF0000");
drawARectangleOnCanvas(originalCanvas2, "#00FF00");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(30); //34 - //2 * 20 + 2 * spacing - 10 //10px is the offset of the second canvas, defined in style
expect(destinationCanvas.height).toBe(20);
expect(canvasData(originalCanvas1, 0, 0, 10, 20)) //14
.toMatchCanvasArea(canvasData(destinationCanvas, 0, 0, 10, 20)); //14
expect(canvasData(originalCanvas2, 0, 0, 20, 20))
.toMatchCanvasArea(canvasData(destinationCanvas, 20 + 0 - 10, 0, 20, 20)); //20 + 10 - 4
done();
}, null);
});
it('should call composeImages on two partially overlapped canvases. Same as above test, but the two canvases have the opposite Z order.', function (done) {
var sources = placeholder.html('<style type="text/css">' +
'#canvasSource2 {position:relative; left:-10px;}' +
'</style>' +
'<div id="test-container" style="width: 600px;height: 400px">' +
'<canvas class="imgsrc" id="canvasSource1" width="20" height="20" title="canvasSource1"></canvas>' +
'<canvas class="imgsrc" id="canvasSource2" width="20" height="20" title="canvasSource2"></canvas>' +
'</div>' +
'<canvas id="myCanvas" width="30" height="15" style="border:1px solid #d3d3d3;"></canvas>'
).find('.imgsrc').toArray();
var originalCanvas1 = document.getElementById("canvasSource1");
var originalCanvas2 = document.getElementById("canvasSource2");
var destinationCanvas = document.getElementById("myCanvas");
drawARectangleOnCanvas(originalCanvas1, "#FF0000");
drawARectangleOnCanvas(originalCanvas2, "#00FF00");
sources.reverse(); //make sure the images are composed in the inverse order
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(30); //34 - //2 * 20 + 2 * spacing - 10 //10px is the offset of the second canvas, defined in style
expect(destinationCanvas.height).toBe(20);
expect(canvasData(originalCanvas1, 0, 0, 20, 20))
.toMatchCanvasArea(canvasData(destinationCanvas, 0, 0, 20, 20));
expect(canvasData(originalCanvas2, 0, 0, 20 - 10 + 0, 20)) //20 - 10 + 4
.toMatchCanvasArea(canvasData(destinationCanvas, 20, 0, 20 - 10 + 0, 20)); //20 - 10 + 4
done();
}, null);
});
it('should call composeImages on two separate canvases, where one canvas is outside of view area', function (done) {
var sources = placeholder.html('<style type="text/css">' +
'#canvasSource2 {position:relative; left:-100px;}' +
'</style>' +
'<div id="test-container" style="width: 600px;height: 400px">' +
'<canvas class="imgsrc" id="canvasSource1" width="20" height="20" title="canvasSource1"></canvas>' +
'<canvas class="imgsrc" id="canvasSource2" width="20" height="20" title="canvasSource2"></canvas>' +
'</div>' +
'<canvas id="myCanvas" width="30" height="15" style="border:1px solid #d3d3d3;"></canvas>'
).find('.imgsrc').toArray();
var originalCanvas1 = document.getElementById("canvasSource1");
var originalCanvas2 = document.getElementById("canvasSource2");
var destinationCanvas = document.getElementById("myCanvas");
drawARectangleOnCanvas(originalCanvas1, "#FF0000");
drawARectangleOnCanvas(originalCanvas2, "#00FF00");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(100 - 0); //100 - 4
expect(destinationCanvas.height).toBe(20);
expect(canvasData(originalCanvas1, 0, 0, 20, 20))
.toMatchCanvasArea(canvasData(destinationCanvas, 100 - 20 - 0, 0, 20, 20)); //100 - 20 - 10 + 6
expect(canvasData(originalCanvas2, 0, 0, 20, 20))
.toMatchCanvasArea(canvasData(destinationCanvas, 0, 0, 20, 20));
done();
}, null);
});
it('should call composeImages on one canvas and an SVG, which are totally overlapped with transparency', function (done) {
var sources = placeholder.html('<style type="text/css">' +
'#canvasSource1 {position:relative; left:-40px; top:-80px;}' +
'circle { stroke: black; stroke-width: 2px;}' +
'</style>' +
'<div id="test-container" style="width: 600px;height: 400px">' +
'<svg class="imgsrc" id="svgSource1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" width="100" height="100" title="svg1">' +
'<circle id="c1" cx="10" cy="10" r="5" style="fill:red"/>' +
'<circle id="c2" cx="30" cy="40" r="7" style="fill:#00FF00"/>' +
'<circle id="c3" cx="50" cy="70" r="9" style="fill:blue"/>' +
'</svg>' +
'<canvas class="imgsrc" id="canvasSource1" width="20" height="20" title="canvasSource1"></canvas>' +
'</div>' +
'<canvas id="myCanvas" width="150" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('.imgsrc').toArray();
var originalCanvas1 = document.getElementById("canvasSource1");
var destinationCanvas = document.getElementById("myCanvas");
drawARectangleOnCanvas(originalCanvas1, "#FF0000");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(100);
expect(destinationCanvas.height).toBe(100);
expect(canvasData(originalCanvas1, 0, 0, 20, 20))
.toMatchCanvasArea(canvasData(destinationCanvas, 100 - 40 + 0, 0, 20, 20)); //100 - 40 + 4
expect(canvasData(destinationCanvas, 10, 10, 1, 1)).toMatchPixelColor([255, 0, 0, 255]);
expect(canvasData(destinationCanvas, 30, 40, 1, 1)).toMatchPixelColor([0, 255, 0, 255]);
expect(canvasData(destinationCanvas, 50, 70, 1, 1)).toMatchPixelColor([0, 0, 255, 255]);
done();
}, null);
});
it('should call composeImages on one canvas and an SVG, which are totally overlapped with transparency. The SVG has a different size than the ones from other tests. One component of the SVG is partially outside of the view area.', function (done) {
var sources = placeholder.html('<style type="text/css">' +
'#canvasSource1 {position:relative; left:-180px; top:-10px;}' +
'circle { stroke: black; stroke-width: 4px;}' +
'</style>' +
'<div id="test-container" style="width: 600px;height: 400px">' +
'<svg class="imgsrc" id="svgSource1" viewBox="0 0 250 150" xmlns="http://www.w3.org/2000/svg" width="250" height="150" title="svg1">' +
'<circle id="c1" cx="230" cy="20" r="15" style="fill:red"/>' +
'<circle id="c2" cx="175" cy="100" r="25" style="fill:#00FF00"/>' +
'<circle id="c3" cx="50" cy="130" r="40" style="fill:blue"/>' +
'</svg>' +
'<canvas class="imgsrc" id="canvasSource1" width="20" height="20" title="canvasSource1"></canvas>' +
'</div>' +
'<canvas id="myCanvas" width="150" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('.imgsrc').toArray();
var originalCanvas1 = document.getElementById("canvasSource1");
var destinationCanvas = document.getElementById("myCanvas");
drawARectangleOnCanvas(originalCanvas1, "#FF0000");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(250);
expect(destinationCanvas.height).toBe(150);
expect(canvasData(originalCanvas1, 0, 0, 20, 20))
.toMatchCanvasArea(canvasData(destinationCanvas, 250 - 180 + 0, 150 - 10 - 20, 20, 20)); //250 - 180 + 4
//circle centers
expect(canvasData(destinationCanvas, 230, 20, 1, 1)).toMatchPixelColor([255, 0, 0, 255]);
expect(canvasData(destinationCanvas, 175, 100, 1, 1)).toMatchPixelColor([0, 255, 0, 255]);
expect(canvasData(destinationCanvas, 50, 130, 1, 1)).toMatchPixelColor([0, 0, 255, 255]);
//other points on circles should match the required colors, because of configured diameters
expect(canvasData(destinationCanvas, 220, 17, 1, 1)).toMatchPixelColor([255, 0, 0, 255]);
expect(canvasData(destinationCanvas, 190, 114, 1, 1)).toMatchPixelColor([0, 255, 0, 255]);
expect(canvasData(destinationCanvas, 80, 149, 1, 1)).toMatchPixelColor([0, 0, 255, 255]);
//verify a pixel from the circle border, if it comes from a black line (almost black, because of antialiasing), as described in svg style
expect(canvasData(destinationCanvas, 79, 102, 1, 1)).toMatchPixelColorWithError([0, 0, 0, 255, 15]);
done();
}, null);
});
it('should call composeImages on one canvas and an SVG, which are totally overlapped with transparency, using external CSS. The SVG has a different size than the ones from other tests. One component of the SVG is partially outside of the view area.', function (done) {
var sources = placeholder.html('<style type="text/css">' +
'#canvasSource1 {position:relative; left:-180px; top:-10px;}' +
'</style>' +
'<div id="test-container" style="width: 600px;height: 400px">' +
'<svg class="imgsrc" id="svgSource1" viewBox="0 0 250 150" xmlns="http://www.w3.org/2000/svg" width="250" height="150" title="svg1">' +
'<circle class="externalCSS" id="c1" cx="230" cy="20" r="15" style="fill:red"/>' +
'<circle class="externalCSS" id="c2" cx="175" cy="100" r="25" style="fill:#00FF00"/>' +
'<circle class="externalCSS" id="c3" cx="50" cy="130" r="40" style="fill:blue"/>' +
'</svg>' +
'<canvas class="imgsrc" id="canvasSource1" width="20" height="20" title="canvasSource1"></canvas>' +
'</div>' +
'<canvas id="myCanvas" width="150" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('.imgsrc').toArray();
var originalCanvas1 = document.getElementById("canvasSource1");
var destinationCanvas = document.getElementById("myCanvas");
drawARectangleOnCanvas(originalCanvas1, "#FF0000");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(250);
expect(destinationCanvas.height).toBe(150);
expect(canvasData(originalCanvas1, 0, 0, 20, 20))
.toMatchCanvasArea(canvasData(destinationCanvas, 250 - 180 + 0, 150 - 10 - 20, 20, 20)); //250 - 180 + 4
//circle centers
expect(canvasData(destinationCanvas, 230, 20, 1, 1)).toMatchPixelColor([255, 0, 0, 255]);
expect(canvasData(destinationCanvas, 175, 100, 1, 1)).toMatchPixelColor([0, 255, 0, 255]);
expect(canvasData(destinationCanvas, 50, 130, 1, 1)).toMatchPixelColor([0, 0, 255, 255]);
//other points on circles should match the required colors, because of configured diameters
expect(canvasData(destinationCanvas, 220, 17, 1, 1)).toMatchPixelColor([255, 0, 0, 255]);
expect(canvasData(destinationCanvas, 190, 114, 1, 1)).toMatchPixelColor([0, 255, 0, 255]);
expect(canvasData(destinationCanvas, 80, 149, 1, 1)).toMatchPixelColor([0, 0, 255, 255]);
//verify a pixel from the circle border, if it comes from a black line (almost black, because of antialiasing), as described in svg style
expect(canvasData(destinationCanvas, 79, 102, 1, 1)).toMatchPixelColorWithError([0, 0, 0, 255, 15]);
done();
}, null);
});
it('should call composeImages on one dynamically created canvas as a source, without being able to compose', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'</div>' +
'<canvas id="myCanvas" width="30" height="15" style="border:1px solid #d3d3d3;"></canvas>'
).find('#canvasSource').toArray();
var originalCanvas = document.createElement('canvas');
originalCanvas.width = 20;
originalCanvas.height = 20;
drawSomeLinesOnCanvas(originalCanvas);
sources.push(originalCanvas);
var destinationCanvas = document.getElementById("myCanvas");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(30);
expect(destinationCanvas.height).toBe(15);
done();
}, null);
});
it('should call composeImages on two dynamically created canvas as sources, without being able to compose', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'</div>' +
'<canvas id="myCanvas" width="30" height="15" style="border:1px solid #d3d3d3;"></canvas>'
).find('#canvasSource').toArray();
var originalCanvas = document.createElement('canvas');
originalCanvas.width = 20;
originalCanvas.height = 20;
drawSomeLinesOnCanvas(originalCanvas);
sources.push(originalCanvas);
originalCanvas = document.createElement('canvas');
originalCanvas.width = 20;
originalCanvas.height = 20;
drawSomeLinesOnCanvas(originalCanvas);
sources.push(originalCanvas);
var destinationCanvas = document.getElementById("myCanvas");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(30);
expect(destinationCanvas.height).toBe(15);
done();
}, null);
});
it('should call composeImages on two dynamically created canvas as sources (with left/top properties set), without being able to compose', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'</div>' +
'<canvas id="myCanvas" width="30" height="15" style="border:1px solid #d3d3d3;"></canvas>'
).find('#canvasSource').toArray();
var originalCanvas = document.createElement('canvas');
originalCanvas.width = 20;
originalCanvas.height = 20;
originalCanvas.left = 0;
originalCanvas.top = 0;
drawSomeLinesOnCanvas(originalCanvas);
sources.push(originalCanvas);
originalCanvas = document.createElement('canvas');
originalCanvas.width = 20;
originalCanvas.height = 20;
originalCanvas.left = 0;
originalCanvas.top = 0;
drawSomeLinesOnCanvas(originalCanvas);
sources.push(originalCanvas);
var destinationCanvas = document.getElementById("myCanvas");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(30);
expect(destinationCanvas.height).toBe(15);
done();
}, null);
});
it('should call composeImages on one canvas as a source and a dynamically generated destination Canvas', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<canvas id="canvasSource" width="20" height="20" title="canvasSource"></canvas>' +
'</div>'
).find('#canvasSource').toArray();
var originalCanvas = document.getElementById("canvasSource");
var destinationCanvas = document.createElement("canvas");
destinationCanvas.width = 30;
destinationCanvas.height = 15;
drawSomeLinesOnCanvas(originalCanvas);
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(20);
expect(destinationCanvas.height).toBe(20);
expect(canvasData(originalCanvas, 0, 0, 20, 20))
.toMatchCanvasArea(canvasData(destinationCanvas, 0, 0, 20, 20));
done();
}, null);
});
xit('should call composeImages on one SVG as a source, which defines only its viewbox, without width and height', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<svg id="svgSource" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" title="svg">' +
'<circle id="c1" cx="10" cy="10" r="5" style="fill:red"/>' +
'<circle id="c2" cx="30" cy="40" r="7" style="fill:#00FF00"/>' +
'<circle id="c3" cx="50" cy="70" r="9" style="fill:blue"/>' +
'</svg>' +
'</div>' +
'<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('svg').toArray();
var destinationCanvas = document.getElementById("myCanvas");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(600);
expect(destinationCanvas.height).toBe(600);
expect(canvasData(destinationCanvas, 10, 10, 1, 1)).toMatchPixelColor([255, 0, 0, 255]);
expect(canvasData(destinationCanvas, 30, 40, 1, 1)).toMatchPixelColor([0, 255, 0, 255]);
expect(canvasData(destinationCanvas, 50, 70, 1, 1)).toMatchPixelColor([0, 0, 255, 255]);
done();
}, null);
});
xit('should call composeImages on one SVG as a source, which defines only its width and height, without its viewbox', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<svg id="svgSource" xmlns="http://www.w3.org/2000/svg" width="100" height="100" title="svg">' +
'<circle id="c1" cx="10" cy="10" r="5" style="fill:red"/>' +
'<circle id="c2" cx="30" cy="40" r="7" style="fill:#00FF00"/>' +
'<circle id="c3" cx="50" cy="70" r="9" style="fill:blue"/>' +
'</svg>' +
'</div>' +
'<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('svg').toArray();
var destinationCanvas = document.getElementById("myCanvas");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(100);
expect(destinationCanvas.height).toBe(100);
expect(canvasData(destinationCanvas, 10, 10, 1, 1)).toMatchPixelColor([255, 0, 0, 255]);
expect(canvasData(destinationCanvas, 30, 40, 1, 1)).toMatchPixelColor([0, 255, 0, 255]);
expect(canvasData(destinationCanvas, 50, 70, 1, 1)).toMatchPixelColor([0, 0, 255, 255]);
done();
}, null);
});
xit('should call composeImages on one potentially unsupported SVG as a source, because it contains "uses". Only its viewBox is defined.', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<svg class="legendLayer" style="width:inherit;height:inherit;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">' +
'<defs>' +
'<symbol id="line" fill="none" viewBox="-5 -5 25 25">' +
'<polyline points="0,15 5,5 10,10 15,0"></polyline>' +
'</symbol>' +
'</defs>' +
'<g>' +
'<use xlink:href="#line" class="legendIcon" x="0em" y="0em" stroke="#82A3D1" stroke-width="2" width="1.5em" height="1.5em"></use>' +
'<text x="0em" y="0em" text-anchor="start"><tspan dx="2em" dy="1.2em">Plot 1</tspan></text>' +
'</g>' +
'<g>' +
'<use xlink:href="#line" class="legendIcon" x="0em" y="1.5em" stroke="#862323" stroke-width="1" width="1.5em" height="1.5em"></use>' +
'<text x="0em" y="1.5em" text-anchor="start"><tspan dx="2em" dy="1.2em">Plot 2</tspan></text>' +
'</g>' +
'</svg>' +
'</div>' +
'<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('svg').toArray();
var destinationCanvas = document.getElementById("myCanvas");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(600);
expect(destinationCanvas.height).toBe(400);
done();
}, null);
});
xit('should call composeImages on one potentially unsupported SVG as a source, because it contains "uses". Only the width and height properties are defined.', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<svg class="legendLayer" style="width:inherit;height:inherit;" xmlns="http://www.w3.org/2000/svg" width="20" height="20">' +
'<defs>' +
'<symbol id="line" fill="none" viewBox="-5 -5 25 25">' +
'<polyline points="0,15 5,5 10,10 15,0"></polyline>' +
'</symbol>' +
'</defs>' +
'<g>' +
'<use xlink:href="#line" class="legendIcon" x="0em" y="0em" stroke="#82A3D1" stroke-width="2" width="1.5em" height="1.5em"></use>' +
'<text x="0em" y="0em" text-anchor="start"><tspan dx="2em" dy="1.2em">Plot 1</tspan></text>' +
'</g>' +
'<g>' +
'<use xlink:href="#line" class="legendIcon" x="0em" y="1.5em" stroke="#862323" stroke-width="1" width="1.5em" height="1.5em"></use>' +
'<text x="0em" y="1.5em" text-anchor="start"><tspan dx="2em" dy="1.2em">Plot 2</tspan></text>' +
'</g>' +
'</svg>' +
'</div>' +
'<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('svg').toArray();
var destinationCanvas = document.getElementById("myCanvas");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(600);
expect(destinationCanvas.height).toBe(400);
done();
}, null);
});
it('should call composeImages on one potentially unsupported SVG as a source, because it contains "uses". ViewBox, width and height properties are defined.', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<svg class="legendLayer" style="width:inherit;height:inherit;" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 100 100">' +
'<defs>' +
'<symbol id="line" fill="none" viewBox="-5 -5 25 25">' +
'<polyline points="0,15 5,5 10,10 15,0"></polyline>' +
'</symbol>' +
'</defs>' +
'<g>' +
'<use xlink:href="#line" class="legendIcon" x="0em" y="0em" stroke="#82A3D1" stroke-width="2" width="1.5em" height="1.5em"></use>' +
'<text x="0em" y="0em" text-anchor="start"><tspan dx="2em" dy="1.2em">Plot 1</tspan></text>' +
'</g>' +
'<g>' +
'<use xlink:href="#line" class="legendIcon" x="0em" y="1.5em" stroke="#862323" stroke-width="1" width="1.5em" height="1.5em"></use>' +
'<text x="0em" y="1.5em" text-anchor="start"><tspan dx="2em" dy="1.2em">Plot 2</tspan></text>' +
'</g>' +
'</svg>' +
'</div>' +
'<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('svg').toArray();
var destinationCanvas = document.getElementById("myCanvas");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(600);
expect(destinationCanvas.height).toBe(400);
done();
}, null);
});
xit('should call composeImages on one empty SVG as a source. This may block composeImages.', function (done) {
var sources = placeholder.html('<div id="test-container" style="width: 600px;height: 400px">' +
'<svg class="legendLayer" style="width:inherit;height:inherit;" xmlns="http://www.w3.org/2000/svg" id="blockingTest">' +
'</svg>' +
'</div>' +
'<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>'
).find('svg').toArray();
var destinationCanvas = document.getElementById("myCanvas");
composeImages(sources, destinationCanvas).then(function() {
expect(destinationCanvas.width).toBe(600);
expect(destinationCanvas.height).toBe(400);
done();
}, null);
});
function drawSomeLinesOnCanvas(canvas) {
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(19, 19);
ctx.moveTo(3, 18);
ctx.lineTo(17, 5);
ctx.stroke();
}
function drawARectangleOnCanvas(canvas, color) {
var ctx = canvas.getContext('2d');
ctx.rect(0, 0, 20, 20);
ctx.fillStyle = color;
ctx.fill();
}
});

View File

@@ -0,0 +1,282 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe("flot errorbars plugin", function() {
var minx = 0, maxx = 200, miny = 0, maxy = 100;
var series, ctx, plotWidth, plotHeight, plotOffset,
getColorOrGradient;
var drawFuncs = {
drawArrow: function(ctx, x, y, radius){
ctx.beginPath();
ctx.moveTo(x + radius, y + radius);
ctx.lineTo(x, y);
ctx.lineTo(x - radius, y + radius);
ctx.stroke();
},
drawSemiCircle: function(ctx, x, y, radius){
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI, false);
ctx.moveTo(x - radius, y);
ctx.lineTo(x + radius, y);
ctx.stroke();
}
};
function validatePointsAreInsideTheAxisRanges(points) {
points.forEach(function(point) {
var x = point[0], y = point[1];
expect(minx <= x && x <= maxx).toBe(true);
expect(miny <= y && y <= maxy).toBe(true);
});
}
function executeHooks(plot, hooks, args) {
args = [plot].concat(args);
for (var i = 0; i < hooks.length; ++i) {
hooks[i].apply(plot, args);
}
}
beforeEach(function() {
ctx = setFixtures('<div id="test-container" style="width: 200px;height: 100px;border-style: solid;border-width: 1px"><canvas id="theCanvas" style="width: 100%; height: 100%" /></div>')
.find('#theCanvas')[0]
.getContext('2d');
plotWidth = 200;
plotHeight = 100;
plotOffset = { top: 0, left: 0 };
getColorOrGradient = jasmine.createSpy().and.returnValue('rgb(10,200,10)');
});
it('should draw nothing when the values are null', function () {
spyOn(ctx, 'moveTo').and.callThrough();
spyOn(ctx, 'lineTo').and.callThrough();
var plot = $.plot($("#test-container"), [[]], {
series: {
lines: {
show: false
}
},
xaxis: {
autoScale: 'none',
min: 0.6,
max: 3.1
},
yaxis: {
autoScale: 'none',
min: 0,
max: 3.5
}
});
expect(ctx.moveTo).not.toHaveBeenCalled();
expect(ctx.lineTo).not.toHaveBeenCalled();
var points = ctx.moveTo.calls.allArgs().concat(
ctx.lineTo.calls.allArgs());
validatePointsAreInsideTheAxisRanges(points);
});
it('should draw lines for error bars on points', function () {
spyOn(ctx, 'lineTo').and.callThrough();
spyOn(ctx, 'moveTo').and.callThrough();
var data1 = [
[1,1,.5,.1,.3],
[2,2,.3,.5,.2],
[3,3,.9,.5,.2],
[1.5,-.05,.5,.1,.3],
[3.15,1.,.5,.1,.3],
[2.5,-1.,.5,.1,.3]
];
var data1_points = {
show: true,
radius: 5,
fillColor: "blue",
errorbars: "xy",
xerr: {show: true, asymmetric: true, upperCap: "-", lowerCap: "-"},
yerr: {show: true, color: "red", upperCap: "-"}
};
var data = [
{color: "blue", points: data1_points, data: data1, label: "data1"}
];
var plot = $.plot($("#test-container"), data, {
series: {
lines: {
show: false
}
},
xaxis: {
autoScale: 'none',
min: 0.6,
max: 3.1
},
yaxis: {
autoScale: 'none',
min: 0,
max: 3.5
}
});
executeHooks(plot, plot.hooks.draw, [ctx]);
expect(ctx.lineTo).toHaveBeenCalled();
expect(ctx.moveTo).toHaveBeenCalled();
var points = ctx.moveTo.calls.allArgs().concat(
ctx.lineTo.calls.allArgs());
validatePointsAreInsideTheAxisRanges(points);
});
it('should draw lines for error bars on lines', function () {
spyOn(ctx, 'lineTo').and.callThrough();
spyOn(ctx, 'moveTo').and.callThrough();
var data3 = [
[1,2,.4],
[2,0.5,.3],
[2.7,2,.5]
];
var data3_points = {
//do not show points
radius: 0,
errorbars: "y",
yerr: {show:true, upperCap: "-", lowerCap: "-", radius: 5}
};
var data = [
{color: "green", lines: {show: true}, points: data3_points, data: data3, label: "data3"},
];
var plot = $.plot($("#test-container"), data, {
series: {
lines: {
show: false
}
},
xaxis: {
autoScale: 'none',
min: 0.6,
max: 3.1
},
yaxis: {
autoScale: 'none',
min: 0,
max: 3.5
}
});
executeHooks(plot, plot.hooks.draw, [ctx]);
expect(ctx.lineTo).toHaveBeenCalled();
expect(ctx.moveTo).toHaveBeenCalled();
var points = ctx.moveTo.calls.allArgs().concat(
ctx.lineTo.calls.allArgs());
validatePointsAreInsideTheAxisRanges(points);
});
it('should draw lines for error bars on bars', function () {
spyOn(ctx, 'lineTo').and.callThrough();
spyOn(ctx, 'moveTo').and.callThrough();
var data4 = [
[1.3, 1],
[1.75, 2.5],
[2.5, 0.5]
];
var data4_points = {
//do not show points
radius: 0,
errorbars: "y",
yerr: {show:true, upperCap: "-", lowerCap: "-", radius: 5}
};
var data4_errors = [0.1, 0.4, 0.2];
for (var i = 0; i < data4.length; i++) {
data4_errors[i] = data4[i].concat(data4_errors[i])
}
var data = [
{color: "orange", bars: {show: true, align: "center", barWidth: 0.25}, data: data4, label: "data4"},
{color: "orange", points: data4_points, data: data4_errors}
];
var plot = $.plot($("#test-container"), data, {
series: {
lines: {
show: false
}
},
xaxis: {
autoScale: 'none',
min: 0.6,
max: 3.1
},
yaxis: {
autoScale: 'none',
min: 0,
max: 3.5
}
});
executeHooks(plot, plot.hooks.draw, [ctx]);
expect(ctx.lineTo).toHaveBeenCalled();
expect(ctx.moveTo).toHaveBeenCalled();
var points = ctx.moveTo.calls.allArgs().concat(
ctx.lineTo.calls.allArgs());
validatePointsAreInsideTheAxisRanges(points);
expect(ctx.lineTo).toHaveBeenCalled();
});
it('should use custom draw functions', function () {
spyOn(drawFuncs, 'drawArrow').and.callThrough();
spyOn(drawFuncs, 'drawSemiCircle').and.callThrough();
var data2 = [
[.7,3,.2,.4],
[1.5,2.2,.3,.4],
[2.3,1,.5,.2]
];
var data2_points = {
show: true,
radius: 5,
errorbars: "y",
yerr: {show:true, asymmetric:true, upperCap: drawFuncs.drawArrow, lowerCap: drawFuncs.drawSemiCircle}
};
var data = [
{color: "red", points: data2_points, data: data2, label: "data2"},
];
var plot = $.plot($("#test-container"), data, {
series: {
lines: {
show: false
}
},
xaxis: {
autoScale: 'none',
min: 0.6,
max: 3.1
},
yaxis: {
autoScale: 'none',
min: 0,
max: 3.5
}
});
executeHooks(plot, plot.hooks.draw, [ctx]);
expect(drawFuncs.drawArrow).toHaveBeenCalled();
expect(drawFuncs.drawSemiCircle).toHaveBeenCalled();
});
});

View File

@@ -0,0 +1,24 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe('fillbetween plugin', function() {
var placeholder, plot, options, dataset;
beforeEach(function() {
dataset = [
{ data: [[0, 2], [1, 2], [2, 4]], lines: { show: true }, color: "rgb(255,50,50)", id: "fillToPlot" },
{ data: [[0, 3], [1, 3], [2, 1]], lines: { show: true, lineWidth: 0, fill: 0.2 }, fillBetween: "fillToPlot", color: "rgb(255,50,50)" }
];
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px">')
.find('#test-container');
});
it('should fill between plots', function () {
plot = $.plot(placeholder, dataset, options);
var series = plot.getData();
var points2 = series[1].datapoints.points;
// second series will have 9 values instead of 6 where every third value is the first series y-value (for a particular datapoint)
expect(points2).toEqual([0, 3, 2, 1, 3, 2, 2, 1, 4]);
});
});

View File

@@ -0,0 +1,46 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe("flatdata plugin", function() {
var placeholder, plot;
var options = {
series: {
shadowSize: 0, // don't draw shadows
lines: { show: false},
points: { show: true, fill: false, symbol: 'circle' }
}
};
beforeEach(function() {
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px">')
.find('#test-container');
});
it('registers an init hook', function () {
var flatdata = $.plot.plugins.find(function(plugin) { return plugin.name === 'flatdata'; });
expect(flatdata).toBeTruthy();
expect(flatdata.init).toBeTruthy();
});
it('writes the x and y values into a single 1D array when the plugin is activated', function () {
options.series.flatdata = true;
plot = $.plot(placeholder, [[10, 20, 30]], options);
var points = plot.getData()[0].datapoints.points;
expect(points[0]).toBe(0);
expect(points[1]).toBe(10);
expect(points[2]).toBe(1);
expect(points[3]).toBe(20);
expect(points[4]).toBe(2);
expect(points[5]).toBe(30);
});
it('works for empty data', function () {
options.series.flatdata = true;
plot = $.plot(placeholder, [[]], options);
var datapoints = plot.getData()[0].datapoints;
expect(datapoints.points.length).toBe(0);
});
});

View File

@@ -0,0 +1,232 @@
describe("flot hover plugin", function () {
var placeholder, plot, options;
var rgba = window.colors.rgba;
var getEntireCanvasData = window.colors.getEntireCanvasData;
var canvasData = window.colors.canvasData;
beforeEach(function () {
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px">')
.find('#test-container');
options = {
grid: { hoverable: true, clickable: true },
pan: { enableTouch: true, active: true },
series: {
lines: {
show: true
},
points: {
show: false
}
}
};
jasmine.clock().install().mockDate();
jasmine.addMatchers(window.colors.jasmineMatchers);
});
afterEach(function() {
jasmine.clock().uninstall();
});
describe('touch hover', function() {
it('tap on plot triggers plothover event', function() {
plot = $.plot(placeholder, [ [ [0, 0], [10, 10] ] ], options);
var eventHolder = plot.getEventHolder(),
axisx = plot.getXAxes()[0],
axisy = plot.getYAxes()[0],
coords = [{x: axisx.p2c(0.5), y: axisy.p2c(-3.5)}],
spy = jasmine.createSpy('spy');
$(plot.getPlaceholder()).on('plothover', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
jasmine.clock().tick(50);
simulate.sendTouchEvents(coords, eventHolder, 'touchend');
expect(spy).toHaveBeenCalled();
expect(spy.calls.count()).toBe(1);
});
it('pan plot triggers plothovercleanup event', function() {
plot = $.plot(placeholder, [ [ [0, 0], [10, 10] ] ], options);
var eventHolder = plot.getEventHolder(),
axisx = plot.getXAxes()[0],
axisy = plot.getYAxes()[0],
coords = [{x: axisx.p2c(0.5), y: axisy.p2c(-3.5)}],
spy = jasmine.createSpy('spy');
$(plot.getPlaceholder()).on('plothovercleanup', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
expect(spy).toHaveBeenCalled();
expect(spy.calls.count()).toBe(1);
});
it('set data to the plot triggers plothovercleanup event', function() {
plot = $.plot(placeholder, [ [ [0, 0], [10, 10] ] ], options);
var spy = jasmine.createSpy('spy');
$(plot.getPlaceholder()).on('plothovercleanup', spy);
plot.setData([1, 2, 3, 4]);
expect(spy).toHaveBeenCalled();
});
});
describe('mouse hover', function() {
beforeEach(function() {
options.series.hoverable = true;
options.series.highlightColor = 'rgba(10, 20, 30, 1)';
});
it('should highlight the point when hovered', function() {
plot = $.plot(placeholder, [ [ [0, 0], [2, 3], [10, 10] ] ], options);
var eventHolder = plot.getEventHolder(),
canvas = eventHolder,
offset = plot.getPlotOffset(),
axisx = plot.getXAxes()[0],
axisy = plot.getYAxes()[0],
x = axisx.p2c(2) + offset.left,
y = axisy.p2c(3) + offset.top,
noButton = 0;
simulate.mouseMove(eventHolder, x, y, noButton);
jasmine.clock().tick(100);
expect(getEntireCanvasData(canvas)).toContainPixelColor(rgba(10, 20, 30, 1));
});
it('should highlight the point when hovered from a small distance', function() {
plot = $.plot(placeholder, [ [ [0, 0], [2, 3], [10, 10] ] ], options);
var eventHolder = plot.getEventHolder(),
canvas = eventHolder,
offset = plot.getPlotOffset(),
epsilon = 2,
axisx = plot.getXAxes()[0],
axisy = plot.getYAxes()[0],
x = axisx.p2c(2) + offset.left + epsilon,
y = axisy.p2c(3) + offset.top - epsilon,
noButton = 0;
simulate.mouseMove(eventHolder, x, y, noButton);
jasmine.clock().tick(100);
expect(getEntireCanvasData(canvas)).toContainPixelColor(rgba(10, 20, 30, 1));
});
it('should not highlight the point when hovered and the grid is not hoverable', function() {
options.grid.hoverable = false;
plot = $.plot(placeholder, [ [ [0, 0], [2, 3], [10, 10] ] ], options);
var eventHolder = plot.getEventHolder(),
canvas = eventHolder,
offset = plot.getPlotOffset(),
axisx = plot.getXAxes()[0],
axisy = plot.getYAxes()[0],
x = axisx.p2c(2) + offset.left,
y = axisy.p2c(3) + offset.top,
noButton = 0;
simulate.mouseMove(eventHolder, x, y, noButton);
jasmine.clock().tick(100);
expect(getEntireCanvasData(canvas)).not.toContainPixelColor(rgba(10, 20, 30, 1));
});
it('should not highlight the point when hovered and the series is not hoverable', function() {
options.series.hoverable = false;
plot = $.plot(placeholder, [ [ [0, 0], [2, 3], [10, 10] ] ], options);
var eventHolder = plot.getEventHolder(),
canvas = eventHolder,
offset = plot.getPlotOffset(),
axisx = plot.getXAxes()[0],
axisy = plot.getYAxes()[0],
x = axisx.p2c(2) + offset.left,
y = axisy.p2c(3) + offset.top,
noButton = 0;
simulate.mouseMove(eventHolder, x, y, noButton);
jasmine.clock().tick(100);
expect(getEntireCanvasData(canvas)).not.toContainPixelColor(rgba(10, 20, 30, 1));
});
it('should unhighlight the previouse point when hovering a new one', function() {
plot = $.plot(placeholder, [ [ [0, 0], [2, 3], [10, 10] ] ], options);
var eventHolder = plot.getEventHolder(),
canvas = eventHolder,
offset = plot.getPlotOffset(),
axisx = plot.getXAxes()[0],
axisy = plot.getYAxes()[0],
x1 = axisx.p2c(2) + offset.left,
y1 = axisy.p2c(3) + offset.top,
x2 = axisx.p2c(10) + offset.left,
y2 = axisy.p2c(10) + offset.top,
r = 5,
noButton = 0;
simulate.mouseMove(eventHolder, x1, y1, noButton);
jasmine.clock().tick(100);
expect(canvasData(canvas, x1 - r, y1 - r, 2 * r, 2 * r)).toContainPixelColor(rgba(10, 20, 30, 1));
expect(canvasData(canvas, x2 - r, y2 - r, 2 * r, 2 * r)).not.toContainPixelColor(rgba(10, 20, 30, 1));
simulate.mouseMove(eventHolder, x2, y2, noButton);
jasmine.clock().tick(100);
expect(canvasData(canvas, x1 - r, y1 - r, 2 * r, 2 * r)).not.toContainPixelColor(rgba(10, 20, 30, 1));
expect(canvasData(canvas, x2 - r, y2 - r, 2 * r, 2 * r)).toContainPixelColor(rgba(10, 20, 30, 1));
});
it('should update the current hover point to the placeholder when the plot created again', function () {
plot = $.plot(placeholder, [ [ [0, 0], [2, 3], [10, 10] ] ], options);
var eventHolder = plot.getEventHolder(),
offset = plot.getPlotOffset(),
axisx = plot.getXAxes()[0],
axisy = plot.getYAxes()[0],
x = axisx.p2c(2) + offset.left,
y = axisy.p2c(3) + offset.top,
noButton = 0;
let evt = simulate.mouseMove(eventHolder, x, y, noButton);
jasmine.clock().tick(1000);
plot = $.plot(placeholder, [ [ [0, 0], [2, 3], [10, 10] ] ], options);
expect(plot.getPlaceholder()[0].lastMouseMoveEvent.originalEvent.x).toEqual(evt.x);
expect(plot.getPlaceholder()[0].lastMouseMoveEvent.originalEvent.y).toEqual(evt.y);
});
it('should highlight a bar when hovered', function() {
options.series.bars = { show: true, barWidth: 0.5 };
options.series.lines = undefined;
plot = $.plot(placeholder, [ [ [0, 3], [1, 5], [2, 4] ] ], options);
var eventHolder = plot.getEventHolder(),
canvas = eventHolder,
offset = plot.getPlotOffset(),
axisx = plot.getXAxes()[0],
axisy = plot.getYAxes()[0],
x = axisx.p2c(1.25) + offset.left,
y = axisy.p2c(2) + offset.top,
noButton = 0;
simulate.mouseMove(eventHolder, x, y, noButton);
jasmine.clock().tick(100);
expect(getEntireCanvasData(canvas)).toContainPixelColor(rgba(10, 20, 30, 1));
});
});
});

View File

@@ -0,0 +1,159 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe('unit tests for the inverted scale functions', function () {
var placeholder;
beforeEach(function () {
placeholder = setFixtures('<div id="test-container" style="width: 800px;height: 400px">')
.find('#test-container');
});
it('should have reverse linear transform set properly', function () {
var plot = $.plot(placeholder, [[0, 1, 2, 3]], {
xaxes: [{
mode: 'linear',
inverted: true,
}]
});
var axis = plot.getAxes().xaxis;
expect(axis.options.transform.name).toBe('invertedTransform');
expect(axis.options.inverseTransform.name).toBe('invertedTransform');
});
it('should have inverted log transform set properly', function () {
var plot = $.plot(placeholder, [[0, 1, 2, 3]], {
xaxes: [{
mode: 'log',
inverted: true,
}]
});
var axis = plot.getAxes().xaxis;
expect(axis.options.transform.name).toBe('invertedLogTransform');
expect(axis.options.inverseTransform.name).toBe('invertedLogInverseTransform');
});
});
describe("integration tests for the inverted scale functions", function () {
var queryPlotForYTicks = function () {
var actualTicks = [];
var yAxisDivs = $('.yAxis');
expect(yAxisDivs.length).toBe(1);
var childDivs = yAxisDivs.find('.tickLabel');
childDivs.each(function (i, e) {
actualTicks.push({
yPos: e.y.baseVal[0].value,
tickName: e.textContent,
});
});
return actualTicks
.sort(function (a, b) { return b.yPos - a.yPos })
.map(function (a) { return a.tickName });
};
var queryPlotForXTicks = function () {
var actualTicks = [];
var xAxisDivs = $('.xAxis');
expect(xAxisDivs.length).toBe(1);
var childDivs = xAxisDivs.find('.tickLabel');
childDivs.each(function (i, e) {
actualTicks.push({
xPos: e.x.baseVal[0].value,
tickName: e.textContent,
});
});
return actualTicks
.sort(function (a, b) { return a.xPos - b.xPos })
.map(function (a) { return a.tickName });
};
var placeholder;
beforeEach(function () {
placeholder = setFixtures('<div id="test-container" style="width: 800px;height: 400px">')
.find('#test-container');
});
it('first tick should be max, last tick should be min for linear axis (positive data)', function () {
const data = [
[0, 0],
[1, 1],
[2, 2],
[3, 3]
];
var plot = $.plot(placeholder, [data], {
xaxis: {
mode: 'linear',
inverted: true,
autoScale: 'exact'
},
yaxis: {
mode: 'linear',
inverted: true,
autoScale: 'exact'
}
});
const yTicks = queryPlotForYTicks();
expect(yTicks[0]).toBe('3.0');
expect(yTicks[yTicks.length - 1]).toBe('0.0');
const xTicks = queryPlotForXTicks();
expect(xTicks[0]).toBe('3.0');
expect(xTicks[xTicks.length - 1]).toBe('0.0');
});
it('first tick should be max, last tick should be min for linear axis (negative data)', function () {
const data = [
[-0, -0],
[-1, -1],
[-2, -2],
[-3, -3]
];
var plot = $.plot(placeholder, [data], {
xaxis: {
mode: 'linear',
inverted: true,
autoScale: 'exact'
},
yaxis: {
mode: 'linear',
inverted: true,
autoScale: 'exact'
}
});
const yTicks = queryPlotForYTicks();
expect(yTicks[0]).toBe('0.0');
expect(yTicks[yTicks.length - 1]).toBe('-3.0');
const xTicks = queryPlotForXTicks();
expect(xTicks[0]).toBe('0.0');
expect(xTicks[xTicks.length - 1]).toBe('-3.0');
});
it('first tick should be max, last tick should be min for log axis', function () {
const data = [
[0.1, 100],
[1, 10],
[10, 1],
[100, 0.1]
];
var plot = $.plot(placeholder, [data], {
xaxis: {
mode: 'log',
inverted: true,
autoScale: 'exact'
},
yaxis: {
mode: 'log',
inverted: true,
autoScale: 'exact'
}
});
const yTicks = queryPlotForYTicks();
expect(yTicks[0]).toBe('100');
expect(yTicks[yTicks.length - 1]).toBe('0.1');
const xTicks = queryPlotForXTicks();
expect(xTicks[0]).toBe('100');
expect(xTicks[xTicks.length - 1]).toBe('0.1');
});
});

View File

@@ -0,0 +1,96 @@
describe('flot with large numbers', function() {
var placeholder, plot;
beforeEach(function() {
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px">')
.find('#test-container');
});
describe('on linear axis', function() {
it('should work with large negative and positive numbers', function () {
plot = $.plot(placeholder, [[[0, 1e308], [1, -1e308]]], {});
var yaxis = plot.getAxes().yaxis;
expect(yaxis.max).toBeGreaterThan(1e308);
expect(yaxis.min).toBeLessThan(-1e308);
expect(yaxis.ticks.length).toBeGreaterThan(2);
yaxis.ticks.forEach(function(tick) {
expect(isFinite(tick.v)).toBe(true);
});
});
it('should work with Number.MAX_VALUE and -Number.MAX_VALUE', function () {
plot = $.plot(placeholder, [[[0, Number.MAX_VALUE], [1, -Number.MAX_VALUE]]], {});
var yaxis = plot.getAxes().yaxis;
expect(yaxis.ticks.length).toBeGreaterThan(2);
yaxis.ticks.forEach(function(tick) {
expect(isFinite(tick.v)).toBe(true);
});
});
it('should work with large numbers and large navigation offsets', function () {
plot = $.plot(placeholder, [[[0, 1e308], [1, -1e308]]], {
yaxes: [{
offset: {below: -1e308, above: 1e308}
}]
});
var yaxis = plot.getAxes().yaxis;
expect(yaxis.max).toBeGreaterThan(1e308);
expect(yaxis.min).toBeLessThan(-1e308);
expect(yaxis.ticks.length).toBeGreaterThan(2);
yaxis.ticks.forEach(function(tick) {
expect(isFinite(tick.v)).toBe(true);
});
});
});
describe('on logaritmic axis', function() {
it('should work with large positive numbers', function () {
plot = $.plot(placeholder, [[[0, 1.1e308], [1, 0]]], {
yaxis: {mode: 'log'}});
var yaxis = plot.getAxes().yaxis;
expect(yaxis.max).toBeGreaterThan(1e308);
expect(yaxis.ticks.length).toBeGreaterThan(2);
yaxis.ticks.forEach(function(tick) {
expect(isFinite(tick.v)).toBe(true);
});
});
it('should work with Number.MAX_VALUE', function () {
plot = $.plot(placeholder, [[[0, Number.MAX_VALUE], [1, 0]]], {
yaxis: {mode: 'log'}});
var yaxis = plot.getAxes().yaxis;
expect(yaxis.ticks.length).toBeGreaterThan(2);
yaxis.ticks.forEach(function(tick) {
expect(isFinite(tick.v)).toBe(true);
});
});
it('should work with large numbers and large navigation offsets', function () {
plot = $.plot(placeholder, [[[0, 1e308], [1, 0]]], {
yaxes: [{
offset: {below: -1e308, above: 1e308},
mode: 'log'
}]
});
var yaxis = plot.getAxes().yaxis;
expect(yaxis.max).toBeGreaterThan(1e308);
expect(yaxis.min).toEqual(0.1);
expect(yaxis.ticks.length).toBeGreaterThan(2);
yaxis.ticks.forEach(function(tick) {
expect(isFinite(tick.v)).toBe(true);
});
});
});
});

View File

@@ -0,0 +1,107 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe("flot legend plugin", function() {
var placeholder, plot;
var options, legendContainer, legendSettings
beforeEach(function() {
var legendSettings = {
position: "nw",
show: true,
container: null
};
options = {
legend: legendSettings,
series: {
shadowSize: 0, // don't draw shadows
}
};
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px">')
.find('#test-container');
});
var positions = ['nw', 'ne', 'sw', 'se'];
positions.forEach(function (pos) {
it ('shold draw a legend over graph at cardinal position: ' + pos + ', if a container is not provided', function () {
options.legend.position = pos;
plot = $.plot(placeholder, [[1, 3, 5, 6]], options);
var legend = document.getElementsByClassName('legend')[0];
expect(legend.style.position).toBe('absolute');
switch (pos) {
case "nw":
expect(legend.style.top).toContain('px')
expect(legend.style.bottom).toBe('');
expect(legend.style.left).toContain('px')
expect(legend.style.right).toBe('');
break;
case "ne":
expect(legend.style.top).toContain('px')
expect(legend.style.bottom).toBe('');
expect(legend.style.left).toBe('');
expect(legend.style.right).toContain('px')
break;
case "sw":
expect(legend.style.top).toBe('');
expect(legend.style.bottom).toContain('px')
expect(legend.style.left).toContain('px')
expect(legend.style.right).toBe('');
break;
case "se":
expect(legend.style.top).toBe('');
expect(legend.style.bottom).toContain('px')
expect(legend.style.left).toBe('');
expect(legend.style.right).toContain('px')
break;
}
});
});
it('should draw the legend inside the container if one is provided', function(){
var legendContainer = document.createElement("div");
document.body.appendChild(legendContainer);
options.legend.container = legendContainer;
plot = $.plot(placeholder, [[1, 3, 5, 6]], options);
expect(legendContainer.style.width).toContain('em');
expect(legendContainer.style.height).toContain('em');
document.body.removeChild(legendContainer);
});
it('should assign a default plot label if none is provided', function(){
plot = $.plot(placeholder, [[1, 3, 5, 6]], options);
var legendSvg = document.getElementsByClassName('legendLayer')[0];
var firstLegendEntry = legendSvg.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'g')[0];
var entryLabel = firstLegendEntry.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'text')[0];
expect(entryLabel.textContent).toBe('Plot 1');
});
it('should display the plot label', function(){
var label = 'custom label';
options.series.label = label;
plot = $.plot(placeholder, [[1, 3, 5, 6]], options);
var legendSvg = document.getElementsByClassName('legendLayer')[0];
var firstLegendEntry = legendSvg.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'g')[0];
var entryLabel = firstLegendEntry.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'text')[0];
expect(entryLabel.textContent).toBe(label);
});
it('should take into account the show option', function() {
options.legend.show = false;
plot = $.plot(placeholder, [[1, 3, 5, 6]], options);
var legendSvg = document.getElementsByClassName('legendLayer')[0];
expect(legendSvg).toBe(undefined);
});
});

View File

@@ -0,0 +1,376 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe("unit tests for the log scale functions", function() {
var placeholder;
beforeEach(function() {
placeholder = setFixtures('<div id="test-container" style="width: 800px;height: 400px">')
.find('#test-container');
});
it('should use linear scale for low dynamic range intervals', function() {
var plot = $.plot(placeholder, [], {
xaxes: [{
min: 10,
max: 11,
}]
}),
axis, ticks;
axis = plot.getAxes().xaxis;
ticks = $.plot.logTicksGenerator(plot, axis, 10);
expect(ticks).toEqual([10, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11]);
});
xit('should use mixed scale for medium dynamic range intervals', function() {
var plot = $.plot(placeholder, [], {
xaxes: [{
min: 0.2,
max: 8,
}]
}),
axis, ticks,
outputArray = [0.2, 0.4, 0.6, 1, 2, 3, 5, 8 ];
axis = plot.getAxes().xaxis;
ticks = $.plot.logTicksGenerator(plot,axis, 10);
for(i = 0; i < ticks.length; i++) {
expect(ticks[i]).toBeCloseTo(outputArray[i]);
}
});
it('should use log scales for high dynamic range intervals', function() {
var plot = $.plot(placeholder, [], {
xaxes: [{
min: 0.0001,
max: 10000,
}]
}),
axis, ticks,
axis = plot.getAxes().xaxis;
ticks = $.plot.logTicksGenerator(plot,axis, 10);
expect(ticks).toEqual([0.0001, 0.001, 0.01, 0.1, 1, 10, 100, 1000, 10000]);
});
it('should format numbers according to their natural precision', function() {
var plot = $.plot(placeholder, [], {
xaxes: [{mode: 'log'}]
}),
xaxis = plot.getXAxes()[0],
logFormatter = xaxis.tickFormatter,
testVector = [
[1.7000000000000002, '1.7'],
[17.000000000000002, '17'],
[172, '172'],
[1.000, '1'],
[0.0004, '0.0004'],
[0.00004, '4e-5'],
[3.1623E-21, '3e-21']
];
testVector.forEach(function (t) {
var inputValue = t[0],
expectedValue = t[1];
expect(logFormatter(inputValue, xaxis)).toBe(expectedValue);
});
});
it('should custom the specified precision of endpoints', function(){
var plot = $.plot(placeholder, [], {
xaxes: [{mode: 'log'}]
}),
xaxis = plot.getXAxes()[0],
logFormatter = xaxis.tickFormatter,
testVector = [
[1.7000000000000002, '1.700', 3],
[1.7000000000000002, '1.70', 2],
[17.000000000000002, '17.000', 3],
[172, '172.0', 1],
[1.000, '1.000', 3],
[1, '1.00', 2],
[0.00004, '4.0e-5', 3],
[4.13567003E-8, '4.1e-8', 9],
[413.567003E-8, '4.136e-6', 9],
[3.1623E-21, '3e-21', 21],
[4.13567003E+8, '4e8', -9],
[413.567003E+8, '4.1e10', -9],
[3.1623E+21, '3.2e21', -20],
[0, '0', -1]
];
testVector.forEach(function (t) {
var inputValue = t[0],
expectedValue = t[1],
precision = t[2];
expect(logFormatter(inputValue, xaxis, precision)).toBe(expectedValue);
});
});
it('should handle intervals which starts close to 0', function() {
var testVector = [
[0, 50, [0.1, 100]],
[1E-40, 1.01, [1e-35, 10]],
[1E-40, 1E+40, [1e-39, 1e40]],
[Number.MIN_VALUE, 1e-20, [10e-273, 1e-20]]
];
testVector.forEach(function (t) {
var min = t[0],
max = t[1],
expectedTicks = t[2],
plot = $.plot(placeholder, [], {
xaxes: [{
min: min,
max: max,
}]
}),
axis, ticks;
axis = plot.getAxes().xaxis;
ticks = $.plot.logTicksGenerator(plot, axis);
expect(ticks[0]).toBeCloseTo(expectedTicks[0], 10);
expect(ticks[ticks.length - 1]).toBeCloseTo(expectedTicks[1], 10);
});
});
it('should set axis.min to be less than axis.max', function() {
var plot = $.plot(placeholder, [[0, 1, 2, 3]], {
xaxes: [{
mode: 'log',
offset : { below: -1, above: -1 },
max: 1
}]
}),
axis, ticks,
axis = plot.getAxes().xaxis;
expect(axis.min).toBeLessThan(axis.max);
});
it('should set axis.max to default max if less then axis.min', function() {
var plot = $.plot(placeholder, [[0, 1, 2, 3]], {
xaxes: [{
mode: 'log',
offset : { below: -5, above: -5 },
max: 1
}]
}),
axis, ticks,
axis = plot.getAxes().xaxis;
expect(axis.min).toBe(0.1);
expect(axis.max).toBe(1);
});
it('should set min of axis with no data associated with it to be greater than 0', function() {
var plot = $.plot(placeholder, [[0, 1, 2, 3]], {
xaxes: [
{
mode: 'log',
min: 0,
max: 10
},
{
mode: 'log',
autoScale: 'loose',
min: 0,
max: 10,
show: true
}]
}),
axis,
axis = plot.getXAxes()[1];
expect(axis.min).toBeGreaterThan(0);
});
});
describe("integration tests for log scale functions", function() {
var placeholder;
var compareNumbers = function(a, b) {
return a - b;
}
var queryPlotForYTicks = function() {
var actualTicks = [];
var yAxisDivs = $('.yAxis');
expect(yAxisDivs.length).toBe(1);
var childDivs = yAxisDivs.find('.tickLabel');
childDivs.each(function(i, e) {
actualTicks.push(e.textContent);
});
return actualTicks.sort(compareNumbers);
};
beforeEach(function() {
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px">')
.find('#test-container');
});
it('should use linear scale for low dynamic range intervals', function() {
var lineardata1 = [
[0, 1],
[1, 1.1],
[2, 1.2],
[3, 1.3],
[4, 1.4],
[5, 1.5],
[6, 1.6],
[7, 1.7],
[8, 1.8],
[9, 1.9],
[10, 2]
];
$.plot(placeholder, [lineardata1], {
yaxis: {
mode: 'log',
autoScale: 'exact'
}
});
expect(queryPlotForYTicks()).toEqual(['1', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8', '1.9', '2']);
});
it('should use log scales for high dynamic range intervals', function() {
var logdata1 = [
[0, 0.0001],
[1, 0.001],
[2, 0.01],
[3, 0.1],
[4, 1],
[5, 10],
[6, 100],
[7, 1000],
[8, 10000]
];
$.plot(placeholder, [logdata1], {
yaxis: {
mode: 'log',
autoScale: 'exact'
}
});
expect(queryPlotForYTicks()).toEqual(['0.0001', '0.001', '0.01', '0.1', '1', '10', '100', '1000', '10000']);
});
it('should allow a user specified tick formatter', function() {
var logdata1 = [
[0, 0.0001],
[1, 0.001],
[2, 0.01],
[3, 0.1],
[4, 1],
[5, 10],
[6, 100],
[7, 1000],
[8, 10000]
];
$.plot(placeholder, [logdata1], {
yaxis: {
mode: 'log',
tickFormatter: function () {
return 'log tick';
},
autoScale: 'exact'
}
});
expect(queryPlotForYTicks()).toEqual(['log tick', 'log tick', 'log tick', 'log tick', 'log tick', 'log tick', 'log tick', 'log tick', 'log tick']);
});
it('should set the minimum of the logaxis to minimum datapoint between 0 and 0.1', function() {
var logdata1 = [
[0, 0],
[1, 0.0001],
[2, 0.001],
[3, 0.01],
[4, 0.1],
[5, 1],
[6, 10],
[7, 100]
];
var plot = $.plot(placeholder, [logdata1], {
xaxis: {
mode: 'log',
autoScale: 'exact'
},
yaxis: {
mode: 'log',
autoScale: 'exact'
}
}),
axes = plot.getAxes();
expect(axes.xaxis.min).toBe(0.1);
expect(axes.yaxis.min).toBe(0.0001);
});
it('should multiply the possible ticks with 5 if the original interval is too little', function() {
var logdata = [
[[0, 1E40], [1, 4E40], [2, 8E40], [3, 1E41], [4, 2E41], [5, 4E41]],
[[0, 1000], [1, 1010], [2, 1E4], [3, 1E5]],
[[0, 1], [1, 3], [2, 10], [3, 30], [4, 40], [5, 50]]
],
expectedTicks = [
['1e40', '5e40', '1e41'],
['1000', '5000', '10000', '50000', '100000'],
['1', '5', '10', '50']
],
plot, i;
for (i = 0; i < logdata.length; i++) {
plot = $.plot(placeholder, [logdata[i]], {
yaxis: {
mode: 'log',
autoScale: 'exact'
}
}),
ticks = queryPlotForYTicks();
expect(queryPlotForYTicks()).toEqual(expectedTicks[i]);
}
});
it('should use only power of ten for large intervals', function() {
var logdata = [
[[0, 1], [1, 4E20], [2, 8E30], [3, 4E41]],
[[0, 1000], [1, 1E5], [2, 1E7], [3, 1E10]],
[[0, 1e-12], [1, 1e-5], [2, 10], [3, 30], [4, 40], [5, 500]]
],
expectedTicks = [
['100', '1000000', '1e10', '1e14', '10e17', '1e22', '1e26', '1e30', '1e34', '1e38'],
['1000', '10000', '100000', '1000000', '10000000', '1e8', '10e8', '1e10'],
['1e-11', '1e-9', '1e-7', '1e-5', '0.001', '0.1', '10']
],
plot, i;
for (i = 0; i < logdata.length; i++) {
plot = $.plot(placeholder, [logdata[i]], {
yaxis: {
mode: 'log',
autoScale: 'exact'
}
}),
ticks = queryPlotForYTicks();
expect(queryPlotForYTicks()).toEqual(expectedTicks[i]);
}
});
});

View File

@@ -0,0 +1,494 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe("flot navigate plugin interactions", function () {
'use strict';
var placeholder, plot, eventHolder;
var options = {
xaxes: [{
autoScale: 'exact'
}],
yaxes: [{
autoScale: 'exact'
}],
zoom: {
interactive: true,
active: true,
amount: 10
},
pan: {
interactive: true,
active: true
}
};
beforeEach(function () {
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px">')
.find('#test-container');
jasmine.clock().install();
});
afterEach(function () {
jasmine.clock().uninstall();
});
it('do smart pans on mouse drag by default', function () {
var oldFrameRate = options.pan.frameRate;
options.pan.frameRate = -1;
plot = $.plot(placeholder, [
[[0, 0],
[10, 10]]
], options);
eventHolder = plot.getEventHolder();
var xaxis = plot.getXAxes()[0];
var yaxis = plot.getYAxes()[0];
// drag almost horizontally snap to x direction
simulate.mouseDown(eventHolder, 50, 70);
simulate.mouseMove(eventHolder, 50, 70);
simulate.mouseMove(eventHolder, 50 + plot.width(), 80);
expect(xaxis.min).toBe(-10);
expect(xaxis.max).toBe(0);
expect(yaxis.min).toBe(0);
expect(yaxis.max).toBe(10);
simulate.mouseUp(eventHolder, 50 + plot.width(), 80);
expect(xaxis.min).toBe(-10);
expect(xaxis.max).toBe(0);
expect(yaxis.min).toBe(0);
expect(yaxis.max).toBe(10);
// drag almost vertically snap to y direction
simulate.mouseDown(eventHolder, 50, 70);
simulate.mouseMove(eventHolder, 50, 70);
simulate.mouseMove(eventHolder, 60, 70 + plot.height());
expect(xaxis.min).toBe(-10);
expect(xaxis.max).toBe(0);
expect(yaxis.min).toBe(10);
expect(yaxis.max).toBe(20);
simulate.mouseUp(eventHolder, 60, 70 + plot.height());
expect(xaxis.min).toBe(-10);
expect(xaxis.max).toBe(0);
expect(yaxis.min).toBe(10);
expect(yaxis.max).toBe(20);
// cover finite frame rate case
plot.destroy();
options.pan.frameRate = 10;
plot = $.plot(placeholder, [
[[0, 0],
[10, 10]]
], options);
eventHolder = plot.getEventHolder();
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
// drag diagonally do not snap
simulate.mouseDown(eventHolder, plot.width() - 50, plot.height() - 70);
simulate.mouseMove(eventHolder, plot.width() - 50, plot.height() - 70);
jasmine.clock().tick(100);
simulate.mouseMove(eventHolder, -50, -70);
jasmine.clock().tick(100);
expect(xaxis.min).toBe(10);
expect(xaxis.max).toBe(20);
expect(yaxis.min).toBe(-10);
expect(yaxis.max).toBe(0);
simulate.mouseUp(eventHolder, -50, -70);
expect(xaxis.min).toBe(10);
expect(xaxis.max).toBe(20);
expect(yaxis.min).toBe(-10);
expect(yaxis.max).toBe(0);
options.pan.frameRate = oldFrameRate;
});
it('do non-smart pans on mouse drag in non-smart pan mode', function () {
var oldPanMode = options.pan.mode;
options.pan.mode = 'manual';
var oldFrameRate = options.pan.frameRate;
options.pan.frameRate = -1;
plot = $.plot(placeholder, [
[[0, 0],
[10, 10]]
], options);
eventHolder = plot.getEventHolder();
var xaxis = plot.getXAxes()[0];
var yaxis = plot.getYAxes()[0];
// drag almost horizontally do not snap
var movement = { x: [50, 50 + plot.width()], y: [70, 80] };
simulate.mouseDown(eventHolder, movement.x[0], movement.y[0]);
simulate.mouseMove(eventHolder, movement.x[0], movement.y[0]);
simulate.mouseMove(eventHolder, movement.x[1], movement.y[1]);
expect(xaxis.min).toBe(-10);
expect(xaxis.max).toBe(0);
expect(yaxis.min).toBeGreaterThan(0);
expect(yaxis.max).toBeGreaterThan(10);
simulate.mouseUp(eventHolder, movement.x[1], movement.y[1]);
// cover finite frame rate case
plot.destroy();
options.pan.frameRate = 10;
plot = $.plot(placeholder, [
[[0, 0],
[10, 10]]
], options);
eventHolder = plot.getEventHolder();
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
// drag almost vertically do not snap
movement = { x: [50, 60], y: [70, 70 + plot.height()] };
simulate.mouseDown(eventHolder, movement.x[0], movement.y[0]);
simulate.mouseMove(eventHolder, movement.x[0], movement.y[0]);
jasmine.clock().tick(100);
simulate.mouseMove(eventHolder, movement.x[1], movement.y[1]);
jasmine.clock().tick(100);
expect(xaxis.min).toBeLessThan(0);
expect(xaxis.max).toBeLessThan(10);
expect(yaxis.min).toBe(10);
expect(yaxis.max).toBe(20);
simulate.mouseUp(eventHolder, movement.x[1], movement.y[1]);
options.pan.mode = oldPanMode;
options.pan.frameRate = oldFrameRate;
});
it('lock smart pan snap direction on mouse drag in smart-lock pan mode', function () {
var oldPanMode = options.pan.mode;
options.pan.mode = 'smartLock';
var oldFrameRate = options.pan.frameRate;
options.pan.frameRate = -1;
plot = $.plot(placeholder, [
[[0, 0],
[10, 10]]
], options);
eventHolder = plot.getEventHolder();
var xaxis = plot.getXAxes()[0];
var yaxis = plot.getYAxes()[0];
var initialXmin = xaxis.min,
initialXmax = xaxis.max,
initialYmin = yaxis.min,
initialYmax = yaxis.max;
// drag almost horizontally then vertically snap to x direction
simulate.mouseDown(eventHolder, 50, 70);
simulate.mouseMove(eventHolder, 50, 70);
simulate.mouseMove(eventHolder, 50 + plot.width() / 2, 80);
simulate.mouseMove(eventHolder, 50 + plot.width(), 70 + plot.height());
simulate.mouseUp(eventHolder, 50 + plot.width(), 70 + plot.height());
expect(xaxis.min).toBeLessThan(initialXmin);
expect(xaxis.max).toBeLessThan(initialXmax);
expect(yaxis.min).toBe(initialYmin);
expect(yaxis.max).toBe(initialYmax);
// drag almost vertically then horizontally snap to y direction
plot.recenter({});
simulate.mouseDown(eventHolder, 50, 70);
simulate.mouseMove(eventHolder, 50, 70);
simulate.mouseMove(eventHolder, 60, 70 + plot.height());
simulate.mouseMove(eventHolder, 50 + plot.width(), 70 + plot.height());
simulate.mouseUp(eventHolder, 50 + plot.width(), 70 + plot.height());
expect(xaxis.min).toBe(initialXmin);
expect(xaxis.max).toBe(initialXmax);
expect(yaxis.min).toBeGreaterThan(initialYmin);
expect(yaxis.max).toBeGreaterThan(initialYmax);
options.pan.mode = oldPanMode;
options.pan.frameRate = oldFrameRate;
});
it('do not move graph on mouse drag if pan mode is invalid', function () {
var oldPanMode = options.pan.mode;
options.pan.mode = '';
var oldFrameRate = options.pan.frameRate;
options.pan.frameRate = -1;
plot = $.plot(placeholder, [
[[0, 0],
[10, 10]]
], options);
eventHolder = plot.getEventHolder();
var xaxis = plot.getXAxes()[0];
var yaxis = plot.getYAxes()[0];
var initialXmin = xaxis.min,
initialXmax = xaxis.max,
initialYmin = yaxis.min,
initialYmax = yaxis.max;
// do not drag in all cases
simulate.mouseDown(eventHolder, 50, 70);
simulate.mouseMove(eventHolder, 50, 70);
simulate.mouseMove(eventHolder, 50 + plot.width() / 2, 70);
simulate.mouseUp(eventHolder, 50 + plot.width(), 70);
expect(xaxis.min).toBe(initialXmin);
expect(xaxis.max).toBe(initialXmax);
expect(yaxis.min).toBe(initialYmin);
expect(yaxis.max).toBe(initialYmax);
simulate.mouseDown(eventHolder, 50, 70);
simulate.mouseMove(eventHolder, 50, 70);
simulate.mouseMove(eventHolder, 50, 70 + plot.height());
simulate.mouseUp(eventHolder, 50, 70 + plot.height());
expect(xaxis.min).toBe(initialXmin);
expect(xaxis.max).toBe(initialXmax);
expect(yaxis.min).toBe(initialYmin);
expect(yaxis.max).toBe(initialYmax);
options.pan.mode = oldPanMode;
options.pan.frameRate = oldFrameRate;
});
it('zooms out on mouse scroll down', function () {
plot = $.plot(placeholder, [
[[0, 0],
[10, 10]]
], options);
var xaxis = plot.getXAxes()[0];
var yaxis = plot.getYAxes()[0];
var clientX = plot.getPlotOffset().left + xaxis.p2c(0);
var clientY = plot.getPlotOffset().top + yaxis.p2c(0);
eventHolder = plot.getEventHolder();
simulate.mouseWheel(eventHolder, clientX, clientY, 0, 100);
/*
I would really like better precission but:
* the browsers may place the graph to fractional pixel coordinates
* we can only deliver mouse events at integer coordinates
* so we can't align precisely our mouse clicks with a point specified in plot coordinates
hence our precission sucks.
But this test isn't about precission, so we are fine
*/
expect(xaxis.min).toBeCloseTo(0, 0);
expect(xaxis.max).toBeCloseTo(100, 0);
expect(yaxis.min).toBeCloseTo(0, 0);
expect(yaxis.max).toBeCloseTo(100, 0);
});
it('zooms in on mouse scroll up', function () {
plot = $.plot(placeholder, [
[[0, 0],
[10, 10]]
], options);
var xaxis = plot.getXAxes()[0];
var yaxis = plot.getYAxes()[0];
var clientX = plot.getPlotOffset().left + xaxis.p2c(0);
var clientY = plot.getPlotOffset().top + yaxis.p2c(0);
eventHolder = plot.getEventHolder();
simulate.mouseWheel(eventHolder, clientX, clientY, 0, -100);
/*
I would really like better precission but:
* the browsers may place the graph to fractional pixel coordinates
* we can only deliver mouse events at integer coordinates
* so we can't align precisely our mouse clicks with a point specified in plot coordinates
hence our precission sucks.
But this test isn't about precission, so we are fine
*/
expect(xaxis.min).toBeCloseTo(0, 1);
expect(xaxis.max).toBeCloseTo(1, 1);
expect(yaxis.min).toBeCloseTo(0, 1);
expect(yaxis.max).toBeCloseTo(1, 1);
});
it('constrains the mouse scroll zoom to the hovered axis ', function () {
plot = $.plot(placeholder, [
[[0, 0],
[10, 10]]
], options);
var xaxis = plot.getXAxes()[0];
var yaxis = plot.getYAxes()[0];
var clientX = plot.getPlotOffset().left + xaxis.p2c(0);
var clientY = xaxis.box.top + xaxis.box.height/2;
eventHolder = plot.getEventHolder();
simulate.mouseWheel(eventHolder, clientX, clientY, 0, -100);
expect(xaxis.min).toBeCloseTo(0, 1);
expect(xaxis.max).toBeCloseTo(1, 1);
expect(yaxis.min).toBeCloseTo(0, 1);
expect(yaxis.max).toBeCloseTo(10, 1);
});
it('zooms out proportional with the deltaY on Mac platforms', function () {
var smallAmount = 0.4,
largerAmount = 0.8,
plot1Ranges = plotAndScroll(smallAmount),
plot2Ranges = plotAndScroll(largerAmount);
expect(plot1Ranges.xaxisMin).toBeLessThan(plot2Ranges.xaxisMin);
expect(plot1Ranges.xaxisMax).toBeGreaterThan(plot2Ranges.xaxisMax);
expect(plot1Ranges.yaxisMin).toBeLessThan(plot2Ranges.yaxisMin);
expect(plot1Ranges.yaxisMax).toBeGreaterThan(plot2Ranges.yaxisMax);
});
it('zooms out regardless the deltaY value on non Mac platforms', function () {
var smallAmount = 40,
largerAmount = 80,
plot1Ranges = plotAndScroll(smallAmount),
plot2Ranges = plotAndScroll(largerAmount);
expect(plot2Ranges.xaxisMin).toBeCloseTo(plot1Ranges.xaxisMin);
expect(plot2Ranges.xaxisMax).toBeCloseTo(plot1Ranges.xaxisMax);
expect(plot2Ranges.yaxisMin).toBeCloseTo(plot1Ranges.yaxisMin);
expect(plot2Ranges.yaxisMax).toBeCloseTo(plot1Ranges.yaxisMax);
});
function plotAndScroll(amount) {
plot = $.plot(placeholder, [
[[0, 0],
[10, 10]]
], options);
var xaxis = plot.getXAxes()[0];
var yaxis = plot.getYAxes()[0];
var clientX = plot.getPlotOffset().left + xaxis.p2c(5);
var clientY = plot.getPlotOffset().top + yaxis.p2c(5);
eventHolder = plot.getEventHolder();
simulate.mouseWheel(eventHolder, clientX, clientY, 0, amount);
return {
xaxisMin: xaxis.min,
xaxisMax: xaxis.max,
yaxisMin: yaxis.min,
yaxisMax: yaxis.max
};
}
it('zooms mode handles event on mouse dblclick', function () {
plot = $.plot(placeholder, [
[[0, 0],
[10, 10]]
], {
xaxes: [{
autoScale: 'exact'
}],
yaxes: [{
autoScale: 'exact'
}],
zoom: {
interactive: false,
highlighted: true
},
pan: {
interactive: true,
highlighted: true
},
selection: {
mode: 'smart',
}});
var xaxis = plot.getXAxes()[0];
var yaxis = plot.getYAxes()[0];
var clientX = plot.getPlotOffset().left + xaxis.p2c(0);
var clientY = plot.getPlotOffset().top + yaxis.p2c(0);
eventHolder = plot.getEventHolder();
var spy = spyOn(eventHolder, 'ondblclick').and.callThrough();
var spyRecenter = jasmine.createSpy('spy');
$(plot.getPlaceholder()).on('re-center', spyRecenter);
simulate.dblclick(eventHolder, 10, 20);
expect(spy).toHaveBeenCalled();
expect(spyRecenter).toHaveBeenCalled();
});
it('shows that the eventHolder is cleared through shutdown when the plot is replaced', function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = spyOn(eventHolder, 'removeEventListener').and.callThrough();
plot = $.plot(placeholder, [[]], options);
expect(spy).toHaveBeenCalledWith('mousewheel', jasmine.any(Function), jasmine.any(Boolean))
expect(spy).toHaveBeenCalledWith('dblclick', jasmine.any(Function), jasmine.any(Boolean));
});
it('do recenter for double click by default', () => {
plot = $.plot(placeholder, [
[[0, 0], [10, 10]]
], {
xaxes: [{ autoScale: 'exact' }],
yaxes: [{ autoScale: 'exact' }],
});
var eventHolder = plot.getEventHolder(),
xaxis = plot.getXAxes()[0],
yaxis = plot.getYAxes()[0],
spyRecenter = jasmine.createSpy('spy');
$(plot.getPlaceholder()).on('re-center', spyRecenter);
plot.pan({ left: 10, top: 10});
simulate.dblclick(eventHolder, 200, 150);
expect(xaxis.options.offset).toEqual({ below: 0, above: 0 });
expect(yaxis.options.offset).toEqual({ below: 0, above: 0 });
expect(spyRecenter).toHaveBeenCalled();
});
it('do not recenter for double click if recenter is disabled', () => {
plot = $.plot(placeholder, [
[[0, 0], [10, 10]]
], {
xaxes: [{ autoScale: 'exact' }],
yaxes: [{ autoScale: 'exact' }],
pan: { interactive: true },
zoom: { interactive: true },
recenter: { interactive: false },
});
var eventHolder = plot.getEventHolder(),
xaxis = plot.getXAxes()[0],
yaxis = plot.getYAxes()[0],
spyRecenter = jasmine.createSpy('spy');
$(plot.getPlaceholder()).on('re-center', spyRecenter);
plot.pan({ left: 10, top: 10});
simulate.dblclick(eventHolder, 200, 150);
expect(xaxis.options.offset).not.toEqual({ below: 0, above: 0 });
expect(yaxis.options.offset).not.toEqual({ below: 0, above: 0 });
expect(spyRecenter).not.toHaveBeenCalled();
});
});

View File

@@ -0,0 +1,820 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe("flot navigate plugin", function () {
var placeholder, plot, options;
beforeEach(function () {
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px">')
.find('#test-container');
options = {
xaxes: [{ autoScale: 'exact' }],
yaxes: [{ autoScale: 'exact' }],
zoom: { interactive: true, active: true, amount: 10 },
pan: { interactive: true, active: true, frameRate: -1 }
};
});
it('provides a zoom, zoomOut, pan, smartPan functions', function () {
plot = $.plot(placeholder, [
[]
], options);
expect(typeof plot.zoom).toBe('function');
expect(typeof plot.zoomOut).toBe('function');
expect(typeof plot.pan).toBe('function');
expect(typeof plot.smartPan).toBe('function');
});
describe('zoom', function () {
it('uses the provided amount', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
plot.zoom({
amount: 2
});
expect(xaxis.min).toBe(2.5);
expect(xaxis.max).toBe(7.5);
expect(yaxis.min).toBeCloseTo(2.5, 7);
expect(yaxis.max).toBeCloseTo(7.5, 7);
});
it('works with autoScale', function () {
var xaxis, yaxis,
opts = {
xaxes: [{ autoScale: 'sliding-window' , min: 0, max: 100}],
yaxes: [{ autoScale: 'loose' }],
zoom: { interactive: true, amount: 10 },
pan: { interactive: true, frameRate: -1 }
};
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], opts);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
plot.zoom({
amount: 4,
center: {
left: 0,
top: plot.height()/2
}
});
expect(xaxis.min).toBe(0);
expect(xaxis.max).toBe(25);
expect(yaxis.min).toBeCloseTo(4.4, 7);
expect(yaxis.max).toBeCloseTo(5.8, 7);
plot.zoom({
amount: -2,
center: {
left: plot.width()/2,
top: plot.height()/2
}
});
expect(xaxis.min).toBeCloseTo(6.25, 2);
expect(xaxis.max).toBe(18.75);
expect(yaxis.min).toBeCloseTo(4.8, 7);
expect(yaxis.max).toBe(5.4);
});
it('uses the amount configured in the plot if none is provided', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
plot.zoom();
expect(xaxis.min).toBe(4.5);
expect(xaxis.max).toBe(5.5);
expect(yaxis.min).toBeCloseTo(4.5, 7);
expect(yaxis.max).toBeCloseTo(5.5, 7);
});
it('uses the provided center', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
plot.zoom({
amount: 2,
center: {
left: 0,
top: plot.height()
}
});
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
expect(xaxis.min).toBe(0);
expect(xaxis.max).toBe(5);
expect(yaxis.min).toBe(0);
expect(yaxis.max).toBe(5);
});
it('uses the provided axes', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
plot.zoom({
amount: 2,
center: {
left: 0,
top: plot.height()
},
axes: plot.getXAxes()
});
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
expect(xaxis.min).toBe(0);
expect(xaxis.max).toBe(5);
expect(yaxis.min).toBe(0);
expect(yaxis.max).toBe(10);
});
it ('doesn\'t got to Infinity and beyond', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[-1, -10e200 ],
[1, 10e200]
]
], options);
plot.zoom({
amount: 10e-200
});
yaxis = plot.getYAxes()[0];
expect(yaxis.min).not.toBe(-Infinity);
expect(yaxis.max).not.toBe(Infinity);
});
it('generates subunitary ticks for X axis', function () {
var xaxis, ticks, middle;
plot = $.plot(placeholder, [
[
[3, 0],
[9, 10]
]
], options);
plot.zoom({
amount: 4,
center: {
left: 0,
top: plot.height()
}
});
xaxis = plot.getXAxes()[0];
expect(xaxis.min).toBe(3);
expect(xaxis.max).toBe(4.5);
ticks = xaxis.ticks;
middle = Math.floor(ticks.length / 2);
expect(ticks[middle- 1].v).toBe(3.6);
expect(ticks[middle].v).toBe(3.8);
expect(ticks[middle + 1].v).toBe(4);
});
it('does not zoom for active false', function () {
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], {
xaxes: [{ autoScale: 'exact' }],
yaxes: [{ autoScale: 'exact' }],
zoom: { interactive: true, active: false, amount: 10 },
pan: { interactive: true, active: false, frameRate: -1 }
});
var eventHolder = plot.getEventHolder(),
xaxis = plot.getXAxes()[0],
yaxis = plot.getYAxes()[0],
initialCoords = [
{x: 3, y: 5},
{x:7, y:9}
],
finalCoords = [
{x: 2, y: 4},
{x: 8, y: 10}
],
midPointCoords = {
x: (xaxis.c2p(finalCoords[0].x - plot.offset().left) + xaxis.c2p(finalCoords[1].x - plot.offset().left)) / 2,
y: (yaxis.c2p(finalCoords[0].y - plot.offset().top) + yaxis.c2p(finalCoords[1].y - plot.offset().top)) / 2
};
simulate.sendTouchEvents(initialCoords, eventHolder, 'touchstart');
simulate.sendTouchEvents(finalCoords, eventHolder, 'touchmove');
simulate.sendTouchEvents(finalCoords, eventHolder, 'touchend');
expect(xaxis.min).toBe(0);
expect(xaxis.max).toBe(10);
expect(yaxis.min).toBe(0);
expect(yaxis.max).toBe(10);
});
describe('with large numbers', function() {
it ('limits the navigation offsets', function () {
var yaxis;
plot = $.plot(placeholder, [
[
[0, -1e308],
[1000, 1e308]
]
], options);
yaxis = plot.getYAxes()[0];
plot.zoom({
amount: 10e-20
});
expect(yaxis.min).toBe(-Number.MAX_VALUE);
expect(yaxis.max).toBe(Number.MAX_VALUE);
expect(isFinite(plot.navigationState().yaxis.navigationOffset.below)).toBe(true);
expect(isFinite(plot.navigationState().yaxis.navigationOffset.above)).toBe(true);
});
})
});
describe('zoomOut', function () {
it('uses the provided amount', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
plot.zoomOut({
amount: 0.5
});
expect(xaxis.min).toBe(2.5);
expect(xaxis.max).toBe(7.5);
expect(yaxis.min).toBeCloseTo(2.5, 7);
expect(yaxis.max).toBeCloseTo(7.5, 7);
});
it('uses the amount configured in the plot if none is provided', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
plot.zoom();
expect(xaxis.min).toBe(4.5);
expect(xaxis.max).toBe(5.5);
expect(yaxis.min).toBeCloseTo(4.5, 7);
expect(yaxis.max).toBeCloseTo(5.5, 7);
});
it('uses the provided center', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
plot.zoomOut({
amount: 0.5,
center: {
left: 0,
top: plot.height()
}
});
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
expect(xaxis.min).toBe(0);
expect(xaxis.max).toBe(5);
expect(yaxis.min).toBe(0);
expect(yaxis.max).toBe(5);
});
it ('doesn\'t got to Infinity and beyond', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[-1, -10e200 ],
[1, 10e200]
]
], options);
plot.zoomOut({
amount: 10e200
});
yaxis = plot.getYAxes()[0];
expect(yaxis.min).not.toBe(-Infinity);
expect(yaxis.max).not.toBe(Infinity);
});
it ('can be disabled per axis for zoom on plot', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
xaxis.options.plotZoom = false;
plot.zoomOut({
amount: 0.5
});
expect(xaxis.min).toBe(0);
expect(xaxis.max).toBe(10);
expect(yaxis.min).toBeCloseTo(2.5, 7);
expect(yaxis.max).toBeCloseTo(7.5, 7);
});
it ('can be disabled per axis for zoom on axis', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
xaxis.options.axisZoom = false;
plot.zoomOut({
amount: 0.5,
axes: [xaxis]
});
expect(xaxis.min).toBe(0);
expect(xaxis.max).toBe(10);
expect(yaxis.min).toBe(0);
expect(yaxis.max).toBe(10);
});
});
describe('smartPan', function () {
it('uses the provided x delta', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
plot.smartPan({
x: -plot.width(),
y: 0
}, plot.navigationState());
expect(xaxis.min).toBe(-10);
expect(xaxis.max).toBe(0);
expect(yaxis.min).toBe(0);
expect(yaxis.max).toBe(10);
});
it('uses the provided y delta', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
plot.smartPan({
x: 0,
y: plot.height(),
}, plot.navigationState());
expect(xaxis.min).toBe(0);
expect(xaxis.max).toBe(10);
expect(yaxis.min).toBe(-10);
expect(yaxis.max).toBe(0);
});
it('snaps to the x direction when delta y is small', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
plot.smartPan({
x: -plot.width(),
y: 1
}, plot.navigationState());
expect(xaxis.min).toBe(-10);
expect(xaxis.max).toBe(0);
expect(yaxis.min).toBe(0);
expect(yaxis.max).toBe(10);
});
it('snaps to the y direction when delta x is small', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
plot.smartPan({
x: 1,
y: plot.height(),
}, plot.navigationState());
expect(xaxis.min).toBe(0);
expect(xaxis.max).toBe(10);
expect(yaxis.min).toBe(-10);
expect(yaxis.max).toBe(0);
});
it('restore xaxis offset on snap on y direction if returns from diagonal snap', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
var initialState = plot.navigationState(0, 0);
plot.smartPan({
x: plot.width(),
y: plot.height(),
}, initialState);
expect(xaxis.min).toBe(10);
expect(xaxis.max).toBe(20);
expect(yaxis.min).toBe(-10);
expect(yaxis.max).toBe(0);
plot.smartPan({
x: plot.width(),
y: 2,
}, initialState);
expect(yaxis.min).toBe(0);
expect(yaxis.max).toBe(10);
});
it ('can be disabled per axis for panning the etire plot', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
xaxis.options.plotPan = false;
plot.smartPan({
x: plot.width(),
y: plot.height(),
}, plot.navigationState());
expect(xaxis.min).toBe(0);
expect(xaxis.max).toBe(10);
expect(yaxis.min).toBe(-10);
expect(yaxis.max).toBe(0);
});
it ('can be disabled per axis for pan on that axis', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
xaxis.options.axisPan = false;
plot.smartPan({
x: plot.width(),
y: plot.height(),
}, plot.navigationState(), [xaxis]);
expect(xaxis.min).toBe(0);
expect(xaxis.max).toBe(10);
expect(yaxis.min).toBe(0);
expect(yaxis.max).toBe(10);
});
it('can pan close to 0 for logaxis', function () {
var xaxis, yaxis;
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], {
xaxes: [{ autoScale: 'exact', mode : 'log'}],
yaxes: [{ autoScale: 'exact' }],
zoom: { interactive: true, active: true, amount: 10 },
pan: { interactive: true, active: true, frameRate: -1 }
});
xaxis = plot.getXAxes()[0];
yaxis = plot.getYAxes()[0];
expect(xaxis.min).toBe(0.1);
expect(xaxis.max).toBe(10);
plot.smartPan({
x: -plot.width(),
y: 0
}, plot.navigationState());
expect(xaxis.min).toBeCloseTo(0.001, 4);
expect(xaxis.max).toBeCloseTo(0.1, 4);
expect(yaxis.min).toBe(0);
expect(yaxis.max).toBe(10);
});
describe('with large numbers', function() {
it ('limits the navigation offsets', function () {
var yaxis;
plot = $.plot(placeholder, [
[
[0, -1e308],
[1000, 1e308]
]
], options);
yaxis = plot.getYAxes()[0];
plot.smartPan({
x: 0,
y: plot.height(),
}, plot.navigationState());
expect(yaxis.min).toBe(-1e308);
expect(yaxis.max).toBeLessThan(0);
expect(isFinite(plot.navigationState().yaxis.navigationOffset.below)).toBe(true);
expect(isFinite(plot.navigationState().yaxis.navigationOffset.above)).toBe(true);
});
})
});
describe('mousePan', function() {
it ('pans on xaxis only', function () {
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
var xaxis = plot.getXAxes()[0],
yaxis = plot.getYAxes()[0],
initialXmin = xaxis.min,
initialXmax = xaxis.max,
eventHolder = plot.getEventHolder(),
pointCoords = [
{ x: xaxis.p2c(4), y: xaxis.box.top + plot.offset().top + 10 },
{ x: xaxis.p2c(5), y: xaxis.box.top + plot.offset().top + 15 }
];
simulate.mouseDown(eventHolder, pointCoords[0].x, pointCoords[0].y);
simulate.mouseMove(eventHolder, pointCoords[0].x, pointCoords[0].y);
simulate.mouseMove(eventHolder, pointCoords[1].x, pointCoords[1].y);
simulate.mouseUp(eventHolder, pointCoords[1].x, pointCoords[1].y);
expect(xaxis.min).toBeCloseTo(xaxis.c2p(xaxis.p2c(initialXmin) + (pointCoords[0].x - pointCoords[1].x)), 0);
expect(xaxis.max).toBeCloseTo(xaxis.c2p(xaxis.p2c(initialXmax) + (pointCoords[0].x - pointCoords[1].x)), 0);
expect(yaxis.min).toBe(0);
expect(yaxis.max).toBe(10);
});
it ('pans on yaxis only', function () {
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], options);
var xaxis = plot.getXAxes()[0],
yaxis = plot.getYAxes()[0],
initialYmin = yaxis.min,
initialYmax = yaxis.max,
eventHolder = plot.getEventHolder(),
pointCoords = [
{ x: xaxis.box.left - 10, y: yaxis.p2c(4) },
{ x: yaxis.p2c(3), y: yaxis.p2c(8) }
];
simulate.mouseDown(eventHolder, pointCoords[0].x, pointCoords[0].y);
simulate.mouseMove(eventHolder, pointCoords[0].x, pointCoords[0].y);
simulate.mouseMove(eventHolder, pointCoords[1].x, pointCoords[1].y);
simulate.mouseUp(eventHolder, pointCoords[1].x, pointCoords[1].y);
expect(xaxis.min).toBe(0);
expect(xaxis.max).toBe(10);
expect(yaxis.min).toBeCloseTo(yaxis.c2p(yaxis.p2c(initialYmin) + (pointCoords[0].y - pointCoords[1].y)), 0);
expect(yaxis.max).toBeCloseTo(yaxis.c2p(yaxis.p2c(initialYmax) + (pointCoords[0].y - pointCoords[1].y)), 0);
});
});
describe('click', function(){
it('on plot activates plot\'s zoom and pan active propriety', function() {
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], {
zoom: { interactive: true, active: false, amount: 10 },
pan: { interactive: true, active: false}
});
var eventHolder = plot.getEventHolder(),
pointCoords = { x: 0, y: plot.height() };
simulate.click(eventHolder, pointCoords.x, pointCoords.y);
expect(plot.getOptions().pan.active).toBe(true);
expect(plot.getOptions().zoom.active).toBe(true);
});
});
describe('mouse dblclick', function(){
it('on plot activates plot\'s zoom and pan active propriety', function() {
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], {
zoom: { interactive: true, active: false, amount: 10 },
pan: { interactive: true, active: false}
});
var eventHolder = plot.getEventHolder(),
pointCoords = { x: 0, y: plot.height() };
simulate.dblclick(eventHolder, pointCoords.x, pointCoords.y);
expect(plot.getOptions().pan.active).toBe(true);
expect(plot.getOptions().zoom.active).toBe(true);
});
it('sends touched axis for double click on axis', function(){
plot = $.plot(placeholder, [
[
[-1, 2],
[11, 12]
]
], options);
var eventHolder = plot.getEventHolder(),
xaxis = plot.getXAxes()[0],
coords = { x: xaxis.p2c(4), y: xaxis.box.top + 10 };
var spyRecenter = jasmine.createSpy('spy');
$(plot.getPlaceholder()).on('re-center', spyRecenter);
simulate.dblclick(eventHolder, coords.x, coords.y);
expect(spyRecenter).toHaveBeenCalled();
expect(spyRecenter.calls.all()[0].args[0].detail.axisTouched).toEqual(xaxis);
});
});
});

View File

@@ -0,0 +1,46 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe('stacking plugin', function() {
var placeholder, plot, options;
beforeEach(function() {
options = {
series: {
stack: true,
bars: {
show: true,
barWidth: 0.6
}
}
};
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px">')
.find('#test-container');
});
it('should accumulate Y values', function () {
var testData = [[[0, 1], [1, 2], [2, 3], [3, 4]], [[0, 4], [1, 3], [2, 2], [3, 1]]];
plot = $.plot(placeholder, testData, options);
var series = plot.getData();
expect(series[0].datapoints.pointsize).toBe(3);
expect(series[1].datapoints.pointsize).toBe(3);
var points1 = series[0].datapoints.points;
// Bottom points should be 0
expect(points1).toEqual([0, 1, 0, 1, 2, 0, 2, 3, 0, 3, 4, 0]);
var points2 = series[1].datapoints.points;
// Bottom points are first series' Y values
expect(points2).toEqual([0, 5, 1, 1, 5, 2, 2, 5, 3, 3, 5, 4]);
});
it('should format data when pointsize = 2', function () {
options.series.flatdata = true;
var testData = [[[0, 1], [1, 2], [2, 3], [3, 4]], [[0, 4], [1, 3], [2, 2], [3, 1]]];
plot = $.plot(placeholder, testData, options);
var series = plot.getData();
expect(series[0].datapoints.pointsize).toBe(3);
expect(series[1].datapoints.pointsize).toBe(3);
expect(series[0].datapoints.points.length).toEqual(12);
expect(series[1].datapoints.points.length).toEqual(12);
});
});

View File

@@ -0,0 +1,48 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe("flot symbol plugin", function() {
var placeholder, plot;
var options;
beforeEach(function() {
options = {
series: {
shadowSize: 0, // don't draw shadows
lines: { show: false},
points: { show: true, fill: false, symbol: 'circle' }
}
};
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px">')
.find('#test-container');
});
it ('provides a list of draw symbols functions', function () {
plot = $.plot(placeholder, [[]], options);
expect(typeof plot.drawSymbol).toBe('object');
})
var shapes = ['square', 'rectangle', 'diamond', 'triangle', 'cross', 'ellipse', 'plus'];
shapes.forEach(function (shape) {
it('should provide a way to draw ' + shape + ' shapes', function () {
plot = $.plot(placeholder, [[]], options);
expect(typeof plot.drawSymbol[shape]).toBe('function')
})
})
shapes.forEach(function (shape) {
it ('' + shape + ' method should be called when the point shape is ' + shape, function () {
options.series.points.symbol = shape;
plot = $.plot(placeholder, [[]], options);
spyOn(plot.drawSymbol, shape).and.callThrough();
plot.setData([[[0, 1], [1, 2]]]);
plot.setupGrid(true);
plot.draw();
expect(plot.drawSymbol[shape]).toHaveBeenCalledTimes(2);
});
});
});

View File

@@ -0,0 +1,128 @@
/* global describe, it, beforeEach, afterEach, expect, setFixtures */
/* jshint browser: true*/
describe('A Flot chart with absolute time axes', function () {
'use strict';
var plot;
var placeholder;
beforeEach(function () {
var fixture = setFixtures('<div id="demo-container" style="width: 800px;height: 600px">').find('#demo-container').get(0);
placeholder = $('<div id="placeholder" style="width: 100%;height: 100%">');
placeholder.appendTo(fixture);
});
afterEach(function () {
if (plot) {
plot.shutdown();
}
});
var firstAndLast = function (arr) {
return [arr[0], arr[arr.length - 1]];
};
var createPlotWithAbsoluteTimeAxis = function (placeholder, data, formatString, base, minTickSize) {
return $.plot(placeholder, data, {
xaxis: {
mode: 'time',
timeformat: formatString,
timeBase: base,
minTickSize: minTickSize,
showTickLabels: 'all'
},
yaxis: {}
});
};
var validateTickLabelFormat = function (ticks, regexFormat) {
var isFormatCorrect = true;
ticks.forEach(function (t) {
if (!t.label.match(regexFormat)) {
isFormatCorrect = false;
}
});
return isFormatCorrect;
};
it('shows time ticks', function () {
plot = createPlotWithAbsoluteTimeAxis(placeholder, [[[0, 1], [1000, 2]]], '%Y/%m/%d %M:%S', 'milliseconds');
expect(firstAndLast(plot.getAxes().xaxis.ticks)).toEqual([
{v: 0, label: '1970/01/01 00:00'},
{v: 1000, label: '1970/01/01 00:01'}
]);
});
describe('date generator', function () {
it('clamps values greater than Date() range to the limit of Date()', function () {
var dateGenerator = $.plot.dateGenerator;
expect(dateGenerator(8640000000000001, {}).date).toEqual(new Date(8640000000000000));
expect(dateGenerator(8640000000000002, {}).date).toEqual(new Date(8640000000000000));
expect(dateGenerator(-8640000000000001, {}).date).toEqual(new Date(-8640000000000000));
expect(dateGenerator(-9640000000000000, {}).date).toEqual(new Date(-8640000000000000));
});
});
describe('timebase in microseconds', function () {
it('supports timestamps given in microseconds', function () {
plot = createPlotWithAbsoluteTimeAxis(placeholder, [[[0, 1], [1000000, 2]]], '%Y/%m/%d %M:%S', 'microseconds');
expect(firstAndLast(plot.getAxes().xaxis.ticks)).toEqual([
{v: 0, label: '1970/01/01 00:00'},
{v: 1000000, label: '1970/01/01 00:01'}
]);
});
});
describe('sub-second ticks', function () {
it('formats ticks to microsecond accuracy', function () {
plot = createPlotWithAbsoluteTimeAxis(placeholder, [[[0, 1], [1000125, 2]]], '%H:%M:%S.%s', 'microseconds');
expect(validateTickLabelFormat(plot.getAxes().xaxis.ticks, /00:00:0\d\.\d{6}/)).toEqual(true);
expect(firstAndLast(plot.getAxes().xaxis.ticks)).toEqual([
{v: 0, label: '00:00:00.000000'},
{v: 1000125, label: '00:00:01.000125'}
]);
});
it('formats ticks to millisecond (3 decimals) accuracy', function () {
plot = createPlotWithAbsoluteTimeAxis(placeholder, [[[0, 1], [1002000, 2]]], '%H:%M:%S.%3s', 'microseconds');
expect(validateTickLabelFormat(plot.getAxes().xaxis.ticks, /00:00:0\d\.\d{3}/)).toEqual(true);
expect(firstAndLast(plot.getAxes().xaxis.ticks)).toEqual([
{v: 0, label: '00:00:00.000'},
{v: 1002000, label: '00:00:01.002'}
]);
});
it('creates ticks automatically to microsecond accuracy', function () {
plot = createPlotWithAbsoluteTimeAxis(placeholder, [[[0, 1], [10, 2]]], null, 'microseconds');
expect(validateTickLabelFormat(plot.getAxes().xaxis.ticks, /00\.\d{6}/)).toEqual(true);
expect(firstAndLast(plot.getAxes().xaxis.ticks)).toEqual([
{v: 0, label: '00.000000'},
{v: 10, label: '00.000010'}
]);
});
it('creates quarter-second ticks', function () {
plot = createPlotWithAbsoluteTimeAxis(placeholder, [[[0, 1], [1, 2]]], null, 'seconds', [250, 'millisecond']);
expect(validateTickLabelFormat(plot.getAxes().xaxis.ticks, /0\d\.(00|25|50|75)/)).toEqual(true);
expect(firstAndLast(plot.getAxes().xaxis.ticks)).toEqual([
{v: 0, label: '00.00'},
{v: 1, label: '01.00'}
])
});
it('creates quarter-millisecond ticks', function () {
plot = createPlotWithAbsoluteTimeAxis(placeholder, [[[0, 1], [1, 2]]], null, 'milliseconds', [250, 'microsecond']);
expect(validateTickLabelFormat(plot.getAxes().xaxis.ticks, /00\.00\d(00|25|50|75)/)).toEqual(true);
expect(firstAndLast(plot.getAxes().xaxis.ticks)).toEqual([
{v: 0, label: '00.00000'},
{v: 1, label: '00.00100'}
])
});
});
});

View File

@@ -0,0 +1,516 @@
/* eslint-disable */
/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
describe("flot touch plugin", function () {
var placeholder, plot, options;
beforeEach(function () {
placeholder = setFixtures('<div id="test-container" style="width: 600px;height: 400px">')
.find('#test-container');
options = {
xaxes: [{ autoScale: 'exact' }],
yaxes: [{ autoScale: 'exact' }],
zoom: { interactive: true, amount: 10, active: true },
pan: { interactive: true, frameRate: -1, enableTouch: true, active: true }
};
});
it('shows that the eventHolder is cleared through shutdown when the plot is replaced', function() {
plot = $.plot(placeholder, [[]], options);
var eventPlaceholder = plot.getEventHolder();
spy = spyOn(eventPlaceholder, 'removeEventListener').and.callThrough();
plot = $.plot(placeholder, [[]], options);
expect(spy).toHaveBeenCalledWith('touchstart', jasmine.any(Function))
expect(spy).toHaveBeenCalledWith('touchmove', jasmine.any(Function));
expect(spy).toHaveBeenCalledWith('touchend', jasmine.any(Function));
});
it('do not stop origin touch event propagation if it is allowed', () => {
jasmine.clock().install().mockDate();
var oldPropagateSupportedGesture = options.propagateSupportedGesture ;
options.propagateSupportedGesture = true;
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('origin touch event handler');
eventHolder.parentNode.addEventListener('touchstart', spy, { once: true });
eventHolder.parentNode.addEventListener('touchmove', spy, { once: true });
eventHolder.parentNode.addEventListener('touchend', spy, { once: true });
var bubbleTouchEvents = [
new UIEvent('touchstart', { bubbles: true }),
new UIEvent('touchmove', { bubbles: true }),
new UIEvent('touchend', { bubbles: true }),
];
bubbleTouchEvents.forEach((event) => {
event.touches = [{ identifier: 0, target: eventHolder }];
eventHolder.dispatchEvent(event);
});
expect(spy).toHaveBeenCalledTimes(3);
options.propagateSupportedGesture = oldPropagateSupportedGesture;
jasmine.clock().uninstall();
});
describe('long tap', function() {
beforeEach(function() {
jasmine.clock().install().mockDate();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it('should trigger the long tap event',function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('long tap handler'),
coords = [{x: 10, y: 20}];
eventHolder.addEventListener('longtap', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
jasmine.clock().tick(1600);
jasmine.clock().tick(1600);
jasmine.clock().tick(1600);
expect(spy).toHaveBeenCalled();
expect(spy.calls.count()).toBe(1);
});
it('should trigger the long tap event even when there is a small move of the touch point',function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('long tap handler'),
initialCoords = [{x: 10, y: 20}],
finalCoords = [{x: 11, y: 21}];
eventHolder.addEventListener('longtap', spy);
simulate.sendTouchEvents(initialCoords, eventHolder, 'touchstart');
simulate.sendTouchEvents(finalCoords, eventHolder, 'touchmove');
jasmine.clock().tick(1600);
expect(spy).toHaveBeenCalled();
expect(spy.calls.count()).toBe(1);
});
it('should not trigger the long tap event when there is a large move of the touch point',function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('long tap handler'),
initialCoords = [{x: 10, y: 20}],
finalCoords = [{x: 100, y: 200}];
eventHolder.addEventListener('longtap', spy);
simulate.sendTouchEvents(initialCoords, eventHolder, 'touchstart');
simulate.sendTouchEvents(finalCoords, eventHolder, 'touchmove');
jasmine.clock().tick(1600);
expect(spy).not.toHaveBeenCalled();
});
it('should not trigger the long tap event when the touch ends too soon',function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('long tap handler'),
coords = [{x: 10, y: 20}];
eventHolder.addEventListener('longtap', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
jasmine.clock().tick(1400);
simulate.sendTouchEvents(coords, eventHolder, 'touchend');
jasmine.clock().tick(200);
expect(spy).not.toHaveBeenCalled();
});
it('should not trigger the long tap event when the plot is replaced', function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('long tap handler'),
coords = [{x: 10, y: 20}];
eventHolder.addEventListener('longtap', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
plot = $.plot(placeholder, [[]], options);
jasmine.clock().tick(1600);
expect(spy).not.toHaveBeenCalled();
});
it('should trigger multiple long tap events',function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('long tap handler'),
coords = [{x: 10, y: 20}];
eventHolder.addEventListener('longtap', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
jasmine.clock().tick(1600);
simulate.sendTouchEvents(coords, eventHolder, 'touchend');
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
jasmine.clock().tick(1600);
simulate.sendTouchEvents(coords, eventHolder, 'touchend');
expect(spy).toHaveBeenCalled();
expect(spy.calls.count()).toBe(2);
});
});
describe('pinch', function() {
beforeEach(function() {
jasmine.clock().install().mockDate();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it('should be able to trigger pinchstart event',function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('pinch handler'),
coords = [{x: 10, y: 20}, {x: 15, y: 20}];
eventHolder.addEventListener('pinchstart', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
expect(spy).toHaveBeenCalled();
expect(spy.calls.count()).toBe(1);
});
it('should not trigger pinch event for plot not active',function() {
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], {
xaxes: [{ autoScale: 'exact' }],
yaxes: [{ autoScale: 'exact' }],
zoom: { interactive: true, active: false, amount: 10 },
pan: { interactive: true, active: false, frameRate: -1 }
});
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('pinch handler'),
coords = [{x: 10, y: 20}, {x: 15, y: 20}];
eventHolder.addEventListener('pinchstart', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
expect(spy).not.toHaveBeenCalled();
expect(spy.calls.count()).toBe(0);
});
it('should not trigger pinch event for only one touch',function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('pinch handler'),
coords = [{x: 10, y: 20}];
eventHolder.addEventListener('pinchstart', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
expect(spy).not.toHaveBeenCalled();
expect(spy.calls.count()).toBe(0);
});
it('should not trigger pinch event for touch outside plot',function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
mockEventHolder = {},
spy = jasmine.createSpy('pinch handler'),
coords = [{x: 10, y: 20}, {x: 15, y: 20}];
eventHolder.addEventListener('pinchstart', spy);
mockEventHolder.dispatchEvent = function() {};
simulate.sendTouchEvents(coords, mockEventHolder, 'touchstart');
expect(spy).not.toHaveBeenCalled();
expect(spy.calls.count()).toBe(0);
});
it('allows default propagation for three touches',function() {
plot = $.plot(placeholder, [], options);
var eventHolder = plot.getEventHolder(),
touchCoords = [{pageX: 10, pageY: 20}, {pageX: 15, pageY: 20}, {pageX: 20, pageY: 25}],
touchStartEvent = new CustomEvent('touchstart'),
touchMoveEvent = new CustomEvent('touchmove');
touchStartEvent.touches = touchCoords;
touchStartEvent.preventDefault = jasmine.createSpy();
touchMoveEvent.touches = touchCoords;
touchMoveEvent.preventDefault = jasmine.createSpy();
eventHolder.dispatchEvent(touchStartEvent);
eventHolder.dispatchEvent(touchMoveEvent);
expect(touchStartEvent.preventDefault).not.toHaveBeenCalled();
expect(touchMoveEvent.preventDefault).not.toHaveBeenCalled();
});
});
describe('pan', function() {
beforeEach(function() {
jasmine.clock().install().mockDate();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it('should be able to trigger pan event',function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('pan handler'),
coords = [{x: 10, y: 20}];
eventHolder.addEventListener('pan', spy);
simulate.sendTouchEvents(coords, eventHolder, 'pan');
expect(spy).toHaveBeenCalled();
expect(spy.calls.count()).toBe(1);
});
it('should not trigger pan event for plot not active',function() {
plot = $.plot(placeholder, [
[
[0, 0],
[10, 10]
]
], {
xaxes: [{ autoScale: 'exact' }],
yaxes: [{ autoScale: 'exact' }],
zoom: { interactive: true, active: false, amount: 10 },
pan: { interactive: true, active: false, frameRate: -1 }
});
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('pan handler'),
coords = [{x: 10, y: 20}];
eventHolder.addEventListener('pan', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
expect(spy).not.toHaveBeenCalled();
expect(spy.calls.count()).toBe(0);
});
it('should not trigger pan event for touch outside plot',function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
mockEventHolder = {},
spy = jasmine.createSpy('pan handler'),
coords = [{x: 10, y: 20}];
eventHolder.addEventListener('panstart', spy);
mockEventHolder.dispatchEvent = function() {};
simulate.sendTouchEvents(coords, mockEventHolder, 'touchstart');
expect(spy).not.toHaveBeenCalled();
expect(spy.calls.count()).toBe(0);
});
});
describe('doubletap', function() {
beforeEach(function() {
jasmine.clock().install().mockDate();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it('should trigger the double tap event', function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('double tap handler'),
coords = [{x: 10, y: 20}];
eventHolder.addEventListener('doubletap', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
jasmine.clock().tick(200);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
expect(spy).toHaveBeenCalled();
expect(spy.calls.count()).toBe(1);
});
it('should trigger the double tap event even when there is a different touch point', function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('double tap handler'),
initialCoords = [{x: 10, y: 20}],
finalCoords = [{x: 11, y: 21}];
eventHolder.addEventListener('doubletap', spy);
simulate.sendTouchEvents(initialCoords, eventHolder, 'touchstart');
jasmine.clock().tick(300);
simulate.sendTouchEvents(finalCoords, eventHolder, 'touchstart');
expect(spy).toHaveBeenCalled();
expect(spy.calls.count()).toBe(1);
});
it('should not trigger the double tap event for a big interval between taps', function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('double tap handler'),
coords = [{x: 10, y: 20}];
eventHolder.addEventListener('doubletap', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
jasmine.clock().tick(1000);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
expect(spy).not.toHaveBeenCalled();
expect(spy.calls.count()).toBe(0);
});
it('should not trigger the double tap event for one of the touches outside plot area', function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
mockEventHolder = {},
spy = jasmine.createSpy('double tap handler'),
initialCoords = [{x: 10, y: 20}],
finalCoords = [{x: 100, y: 200}];
mockEventHolder.dispatchEvent = function() {};
eventHolder.addEventListener('doubletap', spy);
simulate.sendTouchEvents(initialCoords, eventHolder, 'touchstart');
jasmine.clock().tick(100);
simulate.sendTouchEvents(finalCoords, mockEventHolder, 'touchmove');
expect(spy).not.toHaveBeenCalled();
});
});
describe('tap', function() {
beforeEach(function() {
jasmine.clock().install().mockDate();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it('should trigger the tap event', function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('tap handler'),
coords = [{x: 10, y: 20}];
eventHolder.addEventListener('tap', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
jasmine.clock().tick(50);
simulate.sendTouchEvents(coords, eventHolder, 'touchend');
expect(spy).toHaveBeenCalled();
expect(spy.calls.count()).toBe(1);
});
it('should trigger the tap event even when there is a different touch point', function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('tap handler'),
initialCoords = [{x: 10, y: 20}],
finalCoords = [{x: 11, y: 21}];
eventHolder.addEventListener('tap', spy);
simulate.sendTouchEvents(initialCoords, eventHolder, 'touchstart');
jasmine.clock().tick(50);
simulate.sendTouchEvents(finalCoords, eventHolder, 'touchend');
expect(spy).toHaveBeenCalled();
expect(spy.calls.count()).toBe(1);
});
it('should not trigger the tap event for a big interval between taps', function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('tap handler'),
coords = [{x: 10, y: 20}];
eventHolder.addEventListener('tap', spy);
simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
jasmine.clock().tick(200);
simulate.sendTouchEvents(coords, eventHolder, 'touchend');
expect(spy).not.toHaveBeenCalled();
expect(spy.calls.count()).toBe(0);
});
it('should not trigger the tap event for a big interval between taps', function() {
plot = $.plot(placeholder, [[]], options);
var eventHolder = plot.getEventHolder(),
spy = jasmine.createSpy('tap handler'),
initalCoords = [{x: 10, y: 20}],
moveCoords = [{x: 30, y: 60}];;
eventHolder.addEventListener('tap', spy);
simulate.sendTouchEvents(initalCoords, eventHolder, 'touchstart');
simulate.sendTouchEvents(moveCoords, eventHolder, 'touchmove');
jasmine.clock().tick(30);
simulate.sendTouchEvents(moveCoords, eventHolder, 'touchend');
expect(spy).not.toHaveBeenCalled();
expect(spy.calls.count()).toBe(0);
});
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
/* Used in a test from composeImages. */
circle.externalCSS {
stroke: black;
stroke-width: 4px;
}