Skip to content

Commit

Permalink
Merge ae84c70 into 2b1d59e
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewdove1 committed Oct 31, 2019
2 parents 2b1d59e + ae84c70 commit 49b0aa9
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 20 deletions.
52 changes: 51 additions & 1 deletion docs/API.md
Expand Up @@ -1032,7 +1032,7 @@ You can use "plotclick" and "plothover" events like this:
```js
$.plot($("#placeholder"), [ d ], { grid: { clickable: true } });

$("#placeholder").bind("plotclick", function (event, pos, item) {
$("#placeholder").bind("plotclick", function (event, pos, items) {
alert("You clicked at " + pos.x + ", " + pos.y);
// axis coordinates for other axes, if present, are in pos.x2, pos.x3, ...
// if you need global screen coordinates, they are pos.pageX, pos.pageY
Expand All @@ -1052,6 +1052,7 @@ item: {
dataIndex: the index of the point in the data array
series: the series object
seriesIndex: the index of the series
distance: the distance from the cursor
pageX, pageY: the global screen coordinates of the point
}
```
Expand Down Expand Up @@ -1669,6 +1670,55 @@ hooks in the plugins bundled with Flot.

The resize hook is used to be notified after the plot was resized.

- findNearbyItems [phase 7]
```function (canvasX, canvasY, seriesFilter, distance)```

The findNearbyItems hook is used to extend the default behavior of
the flot-provided 'findNearbyItems' function. The hover plugin is
an example of a plugin that leverages this method to return items
that will be highlighted when hovered over. So, as an example, a new
plugin might provide this hook to allow the hover plugin to highlight
points that the flot-provided findNearbyItems method would have
otherwise not found.

canvasX and canvasY are the plot-space coordinates that are being
hovered over. Being in plot-space and not canvas-space, these may
be negative as the plot generally does not take up the whole
canvas.

seriesFilter is a function to determine if the series should be
checked.

radius is the base distance from an item that you should use
as an area to search in if you aren't searching in strict bounds

computeDistance is a function to utilize to compute the distance
from the cursor. It may not be provided, so you will still need
to provide your own distance calculation

items is an array you should push your found items into. It is
unsorted and may hold items from any other plugin or flot's
base calculation.

The item to be returned should have the following:

datapoint - The specific bit of information hovered over

dataindex - The index of the passed in datapoint in a series

series - The information about the series that was hovered over

seriesindex - The index of the series hovered over

distance - Distance, in pixels, between the item and cursor.
If distance is returned as undefined, the item will
be treated as "infinite" distance, and will not be
chosen instead of an item with a distance returned

Distance is added here to the items previously returned from
'findNearbyItem' so that we can decide which item should be
returned as 'item' to 'plothover' and 'plotclick' events

- shutdown [phase 8]

```function (plot, eventHolder)```
Expand Down
14 changes: 12 additions & 2 deletions source/jquery.flot.hover.js
Expand Up @@ -152,12 +152,22 @@ the tooltip from webcharts).
pos.pageX = page.X;
pos.pageY = page.Y;

var item = plot.findNearbyItem(canvasX, canvasY, seriesFilter, distance);
var items = plot.findNearbyItems(canvasX, canvasY, seriesFilter, distance);
var item = items[0];

for (var i = 1; i < items.length; ++i) {
if (item.distance === undefined ||
items[i].distance < item.distance) {
item = items[i];
}
}

if (item) {
// fill in mouse pos for any listeners out there
item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left, 10);
item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top, 10);
} else {
item = null;
}

if (options.grid.autoHighlight) {
Expand All @@ -177,7 +187,7 @@ the tooltip from webcharts).
}
}

plot.getPlaceholder().trigger(eventname, [pos, item]);
plot.getPlaceholder().trigger(eventname, [pos, item, items]);
}

function highlight(s, point, auto) {
Expand Down
64 changes: 47 additions & 17 deletions source/jquery.flot.js
Expand Up @@ -234,6 +234,7 @@ Licensed under the MIT license.
drawSeries: [],
drawAxis: [],
draw: [],
findNearbyItems: [],
axisReserveSpace: [],
bindEvents: [],
drawOverlay: [],
Expand Down Expand Up @@ -345,6 +346,7 @@ Licensed under the MIT license.
plot.computeRangeForDataSeries = computeRangeForDataSeries;
plot.adjustSeriesDataRange = adjustSeriesDataRange;
plot.findNearbyItem = findNearbyItem;
plot.findNearbyItems = findNearbyItems;
plot.findNearbyInterpolationPoint = findNearbyInterpolationPoint;
plot.computeValuePrecision = computeValuePrecision;
plot.computeTickSize = computeTickSize;
Expand Down Expand Up @@ -2492,10 +2494,33 @@ Licensed under the MIT license.
}
}

// returns the data item the mouse is over/ the cursor is closest to, or null if none is found
function findNearbyItems(mouseX, mouseY, seriesFilter, radius, computeDistance) {
var items = findItems(mouseX, mouseY, seriesFilter, radius, computeDistance);
executeHooks(hooks.findNearbyItems, [mouseX, mouseY, seriesFilter, radius, computeDistance, items]);
return items;
}

function findNearbyItem(mouseX, mouseY, seriesFilter, radius, computeDistance) {
var i, j,
item = null,
var items = findNearbyItems(mouseX, mouseY, seriesFilter, radius, computeDistance);
var closest = items[0];

for (var i = 1; i < items.length; ++i) {
if (closest.distance != undefined && items[i].distance < closest.distance) {
closest = items[i];
}
}

if (closest) {
return closest;
}

return null;
}

// returns the data item the mouse is over/ the cursor is closest to, or null if none is found
function findItems(mouseX, mouseY, seriesFilter, radius, computeDistance) {
var i, j, k, foundItems = [],
items = [],
smallestDistance = radius * radius + 1;

for (var i = series.length - 1; i >= 0; --i) {
Expand All @@ -2508,30 +2533,35 @@ Licensed under the MIT license.
var found = findNearbyPoint(s, mouseX, mouseY, radius, smallestDistance, computeDistance);
if (found) {
smallestDistance = found.distance;
item = [i, found.dataIndex];
items.push([i, found.dataIndex]);
}
}

if (s.bars.show && !item) { // no other point can be nearby
if (s.bars.show && !items.length) { // no other point can be nearby
var foundIndex = findNearbyBar(s, mouseX, mouseY);
if (foundIndex >= 0) item = [i, foundIndex];
if (foundIndex) {
items.push([i, foundIndex]);
}
}
}

if (item) {
i = item[0];
j = item[1];
var ps = series[i].datapoints.pointsize;
if (items.length) {
for (k = 0; k < items.length; k++) {
i = items[k][0];
j = items[k][1];
var ps = series[i].datapoints.pointsize;

return {
datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps),
dataIndex: j,
series: series[i],
seriesIndex: i
};
foundItems.push({
datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps),
dataIndex: j,
series: series[i],
seriesIndex: i,
distance: smallestDistance
});
}
}

return null;
return foundItems;
}

function findNearbyPoint (series, mouseX, mouseY, maxDistance, smallestDistance, computeDistance) {
Expand Down
76 changes: 76 additions & 0 deletions tests/jquery.flot.hover.Test.js
Expand Up @@ -258,5 +258,81 @@ describe("flot hover plugin", function () {

expect(getEntireCanvasData(canvas)).toContainPixelColor(rgba(10, 20, 30, 1));
});

it('should call hooked function when canvas is hovered over', function() {
var spy = jasmine.createSpy('spy');

options.hooks = {findNearbyItems: [spy]};
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;

simulate.mouseMove(eventHolder, x, y, noButton);
jasmine.clock().tick(100);

expect(spy).toHaveBeenCalled();
});

it('should pass item returned from hook in items', function() {
var testItem = {distance: 5};
var hook = function(_0, _1, _2, _3, _4, _5, items) {
items.push(testItem);
}

options.hooks = {findNearbyItems: [hook]};
plot = $.plot(placeholder, [ [ [0, 0], [2, 3], [10, 10] ] ], options);

$(plot.getPlaceholder()).on('plothover', function(event, pos, item, items) {
var seenTestItem = false;
for (const i of items) {
if (i === testItem) {
seenTestItem = true;
}
}
expect(seenTestItem).toBe(true);
});

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;

simulate.mouseMove(eventHolder, x, y, noButton);
jasmine.clock().tick(100);
})

it('should choose closest item from items returned by hooks', function() {
var distance = 5,
testItem = {distance: distance};
var hook = function(_0, _1, _2, _3, _4, _5, items) {
items.push(testItem);
}

options.hooks = {findNearbyItems: [hook]};

$(plot.getPlaceholder()).on('plothover', function(event, pos, item, items) {
expect(item.distance < distance).toBe(true);
});

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;

simulate.mouseMove(eventHolder, x, y, noButton);
jasmine.clock().tick(100);
});
});
});

0 comments on commit 49b0aa9

Please sign in to comment.