最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Flot: How do I grab the nearest plotted point to where the cursor is? - Stack Overflow

programmeradmin4浏览0评论

I am trying to grab the nearest plotted point that the cursor is to. I

I found the findNearbyItem function in the jquery.flot.js source that seems to be able to do this, but when I trie calling it manually, I received the ReferenceError: findNearbyItem is not defined error.

This is the function I am referring to:

function findNearbyItem(mouseX, mouseY, seriesFilter) {
    var maxDistance = options.grid.mouseActiveRadius,
        smallestDistance = maxDistance * maxDistance + 1,
        item = null, foundPoint = false, i, j, ps;

    for (i = series.length - 1; i >= 0; --i) {
        if (!seriesFilter(series[i]))
            continue;

        var s = series[i],
            axisx = s.xaxis,
            axisy = s.yaxis,
            points = s.datapoints.points,
            mx = axisx.c2p(mouseX), // prepute some stuff to make the loop faster
            my = axisy.c2p(mouseY),
            maxx = maxDistance / axisx.scale,
            maxy = maxDistance / axisy.scale;

        ps = s.datapoints.pointsize;
        // with inverse transforms, we can't use the maxx/maxy
        // optimization, sadly
        if (axisx.options.inverseTransform)
            maxx = Number.MAX_VALUE;
        if (axisy.options.inverseTransform)
            maxy = Number.MAX_VALUE;

        if (s.lines.show || s.points.show) {
            for (j = 0; j < points.length; j += ps) {
                var x = points[j], y = points[j + 1];
                if (x == null)
                    continue;

                // For points and lines, the cursor must be within a
                // certain distance to the data point
                if (x - mx > maxx || x - mx < -maxx ||
                    y - my > maxy || y - my < -maxy)
                    continue;

                // We have to calculate distances in pixels, not in
                // data units, because the scales of the axes may be different
                var dx = Math.abs(axisx.p2c(x) - mouseX),
                    dy = Math.abs(axisy.p2c(y) - mouseY),
                    dist = dx * dx + dy * dy; // we save the sqrt

                // use <= to ensure last point takes precedence
                // (last generally means on top of)
                if (dist < smallestDistance) {
                    smallestDistance = dist;
                    item = [i, j / ps];
                }
            }
        }

        if (s.bars.show && !item) { // no other point can be nearby
            var barLeft = s.bars.align == "left" ? 0 : -s.bars.barWidth/2,
                barRight = barLeft + s.bars.barWidth;

            for (j = 0; j < points.length; j += ps) {
                var x = points[j], y = points[j + 1], b = points[j + 2];
                if (x == null)
                    continue;

                // for a bar graph, the cursor must be inside the bar
                if (series[i].bars.horizontal ?
                    (mx <= Math.max(b, x) && mx >= Math.min(b, x) &&
                     my >= y + barLeft && my <= y + barRight) :
                    (mx >= x + barLeft && mx <= x + barRight &&
                     my >= Math.min(b, y) && my <= Math.max(b, y)))
                        item = [i, j / ps];
            }
        }
    }

    if (item) {
        i = item[0];
        j = item[1];
        ps = series[i].datapoints.pointsize;

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

    return null;
}

If there are alternate ways of solving this problem, please let me know.

I am trying to grab the nearest plotted point that the cursor is to. I

I found the findNearbyItem function in the jquery.flot.js source that seems to be able to do this, but when I trie calling it manually, I received the ReferenceError: findNearbyItem is not defined error.

This is the function I am referring to:

function findNearbyItem(mouseX, mouseY, seriesFilter) {
    var maxDistance = options.grid.mouseActiveRadius,
        smallestDistance = maxDistance * maxDistance + 1,
        item = null, foundPoint = false, i, j, ps;

    for (i = series.length - 1; i >= 0; --i) {
        if (!seriesFilter(series[i]))
            continue;

        var s = series[i],
            axisx = s.xaxis,
            axisy = s.yaxis,
            points = s.datapoints.points,
            mx = axisx.c2p(mouseX), // prepute some stuff to make the loop faster
            my = axisy.c2p(mouseY),
            maxx = maxDistance / axisx.scale,
            maxy = maxDistance / axisy.scale;

        ps = s.datapoints.pointsize;
        // with inverse transforms, we can't use the maxx/maxy
        // optimization, sadly
        if (axisx.options.inverseTransform)
            maxx = Number.MAX_VALUE;
        if (axisy.options.inverseTransform)
            maxy = Number.MAX_VALUE;

        if (s.lines.show || s.points.show) {
            for (j = 0; j < points.length; j += ps) {
                var x = points[j], y = points[j + 1];
                if (x == null)
                    continue;

                // For points and lines, the cursor must be within a
                // certain distance to the data point
                if (x - mx > maxx || x - mx < -maxx ||
                    y - my > maxy || y - my < -maxy)
                    continue;

                // We have to calculate distances in pixels, not in
                // data units, because the scales of the axes may be different
                var dx = Math.abs(axisx.p2c(x) - mouseX),
                    dy = Math.abs(axisy.p2c(y) - mouseY),
                    dist = dx * dx + dy * dy; // we save the sqrt

                // use <= to ensure last point takes precedence
                // (last generally means on top of)
                if (dist < smallestDistance) {
                    smallestDistance = dist;
                    item = [i, j / ps];
                }
            }
        }

        if (s.bars.show && !item) { // no other point can be nearby
            var barLeft = s.bars.align == "left" ? 0 : -s.bars.barWidth/2,
                barRight = barLeft + s.bars.barWidth;

            for (j = 0; j < points.length; j += ps) {
                var x = points[j], y = points[j + 1], b = points[j + 2];
                if (x == null)
                    continue;

                // for a bar graph, the cursor must be inside the bar
                if (series[i].bars.horizontal ?
                    (mx <= Math.max(b, x) && mx >= Math.min(b, x) &&
                     my >= y + barLeft && my <= y + barRight) :
                    (mx >= x + barLeft && mx <= x + barRight &&
                     my >= Math.min(b, y) && my <= Math.max(b, y)))
                        item = [i, j / ps];
            }
        }
    }

    if (item) {
        i = item[0];
        j = item[1];
        ps = series[i].datapoints.pointsize;

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

    return null;
}

If there are alternate ways of solving this problem, please let me know.

Share edited Jul 9, 2013 at 18:10 Louis93 asked Jul 9, 2013 at 17:42 Louis93Louis93 3,9219 gold badges53 silver badges94 bronze badges 3
  • 1 In case anyone else reads this and is mystified, OP is having an issue with flot – André Dion Commented Jul 9, 2013 at 18:00
  • Added an identifier in the question, thanks. – Louis93 Commented Jul 9, 2013 at 18:03
  • You should also add some code that shows everyone what you're trying to do. – André Dion Commented Jul 9, 2013 at 18:04
Add a ment  | 

3 Answers 3

Reset to default 7 +100

What's your use case for this? If you increase the mouseActiveRadius option to something large flot will find the closest point to the cursor for you.

var options = {
    grid: { 
        hoverable: true, 
        mouseActiveRadius: 1000
    }
}

Example here.

EDIT

Yes, you can use the plothover event to retrieve the highlighted point.

$("#placeholder").bind("plothover", function (event, pos, item) {
    if (item){
        var x = item.datapoint[0].toFixed(2),
            y = item.datapoint[1].toFixed(2);
        console.log("x:" + x + ", " + "y:" + y);
    }
});

Updated Fiddle here.

That's an internal function of flot, but you can easily recreate the same functionality yourself. All you need to do is iterate through the points in your data series and pare their location to your mouse pointer (Pythagoras should be able to help you here).

As for the reason why you see: ReferenceError: findNearbyItem is not defined see this. Applying this little patch by hand will make function public.

发布评论

评论列表(0)

  1. 暂无评论