Есть ли способ изменить цвет графиков в jQuery flot, не перерисовывая весь график? - PullRequest
7 голосов
/ 07 мая 2010

У меня есть график, который я рисую, используя flot. Я хочу изменить цвета графиков данных, когда кто-то наводит курсор на текст. В настоящее время я делаю это, перерисовывая всю диаграмму каждый раз, когда мне нужно что-то выделить. Это довольно медленно (около 30 миллисекунд для простого графика, до 100 для более сложного графика). Поскольку все, что я хочу сделать, это изменить цвет, есть ли более быстрое решение?

1 Ответ

12 голосов
/ 12 мая 2010

Есть немедленные шаги, которые вы можете предпринять, чтобы оптимизировать процесс рисования Flot. Если вам не нужны точки на графике, отключите их, это может значительно сократить время рисования. Вам также следует отключить тени, установив для параметра shadowSize значение 0, чтобы повысить скорость.

Помимо этих двух настроек, вам придется изменить исходный код flot, чтобы иметь возможность выделять серию по отдельности. Я создал патч, который делает именно это, вместе с небольшим плагином, который позволяет выделять серии автоматически или вручную. Патч и плагин могут быть до в три раза быстрее , чем перерисовка всего графика, они также практически исключают время, необходимое для отмены выделения серии, поскольку он использует функцию «оверлея» flot.

Ниже приведен патч для jquery.flot.js и исходный код для плагина highlightSeries, и я создал демонстрационную страницу , которая позволяет увидеть разницу между различными настройками, а также патчем / плагином комбинация.

Флот-патч

--- .\jquery.flot.js
+++ .\jquery.flot.js
@@ -147,6 +147,7 @@
         plot.setData = setData;
         plot.setupGrid = setupGrid;
         plot.draw = draw;
+        plot.drawSeries = drawSeries;
         plot.getPlaceholder = function() { return placeholder; };
         plot.getCanvas = function() { return canvas; };
         plot.getPlotOffset = function() { return plotOffset; };
@@ -164,6 +165,7 @@
         plot.highlight = highlight;
         plot.unhighlight = unhighlight;
         plot.triggerRedrawOverlay = triggerRedrawOverlay;
+        plot.drawOverlay = drawOverlay;
         plot.pointOffset = function(point) {
             return { left: parseInt(axisSpecToRealAxis(point, "xaxis").p2c(+point.x) + plotOffset.left),
                      top: parseInt(axisSpecToRealAxis(point, "yaxis").p2c(+point.y) + plotOffset.top) };
@@ -1059,7 +1061,7 @@
                 drawGrid();

             for (var i = 0; i < series.length; ++i)
-                drawSeries(series[i]);
+                drawSeries(series[i], ctx);

             executeHooks(hooks.draw, [ctx]);

@@ -1265,16 +1267,16 @@
             placeholder.append(html.join(""));
         }

-        function drawSeries(series) {
+        function drawSeries(series, ctx) {
             if (series.lines.show)
-                drawSeriesLines(series);
+                drawSeriesLines(series, ctx);
             if (series.bars.show)
-                drawSeriesBars(series);
+                drawSeriesBars(series, ctx);
             if (series.points.show)
-                drawSeriesPoints(series);
+                drawSeriesPoints(series, ctx);
         }

-        function drawSeriesLines(series) {
+        function drawSeriesLines(series, ctx) {
             function plotLine(datapoints, xoffset, yoffset, axisx, axisy) {
                 var points = datapoints.points,
                     ps = datapoints.pointsize,
@@ -1522,7 +1524,7 @@
             ctx.restore();
         }

-        function drawSeriesPoints(series) {
+        function drawSeriesPoints(series, ctx) {
             function plotPoints(datapoints, radius, fillStyle, offset, circumference, axisx, axisy) {
                 var points = datapoints.points, ps = datapoints.pointsize;

@@ -1675,7 +1677,7 @@
             }
         }

-        function drawSeriesBars(series) {
+        function drawSeriesBars(series, ctx) {
             function plotBars(datapoints, barLeft, barRight, offset, fillStyleCallback, axisx, axisy) {
                 var points = datapoints.points, ps = datapoints.pointsize;

@@ -1942,7 +1944,7 @@

                 if (hi.series.bars.show)
                     drawBarHighlight(hi.series, hi.point);
-                else
+                else if (hi.series.points.show)
                     drawPointHighlight(hi.series, hi.point);
             }
             octx.restore();

плагин highlightSeries

/*
Flot plugin for highlighting series.

    highlightSeries: {
        autoHighlight: true (default) or false
        , color: color
    }

If "autoHighlight" is true (the default) and the plot's "hoverable" setting is true
series are highlighted when the mouse hovers near an item.
"color" is the color of the highlighted series (default is "red").

The plugin also adds two public methods that allow you to highlight and
unhighlight a series manually by specifying a series by label, index or object.

    - highlightSeries(series, [color])

    - unHighlightSeries(series)
*/

(function ($) {
    var log = (function () {
        var out = $("#out");
        return function () {
            if (!arguments) { return; }
            var msg = Array.prototype.slice.call(arguments).join(" ");
            if (!out.length) {
                out = $("#out");
            }
            if (out.length) {
                out.text(msg);
            }
        };
    })();

    var options = {
        highlightSeries: {
            autoHighlight: true
            , color: "black"
            , _optimized: true
            , _debug: false
        }
    };

    function init(plot) {
        var highlightedSeries = {};
        var originalColors = {};

        function highlightSeries(series, color) {
            var
                seriesAndIndex = getSeriesAndIndex(series)
                , options = plot.getOptions().highlightSeries;

            series = seriesAndIndex[1];

            highlightedSeries[seriesAndIndex[0]] = series;
            originalColors[seriesAndIndex[0]] = series.color;

            series.color = color || options.color;

            if (options._debug) { var start = new Date(); }
            if (options._optimized) {
                if (plot.drawOverlay && options._debug) {
                    plot.drawOverlay();
                }
                else {
                    plot.triggerRedrawOverlay();
                }
            }
            else {
                plot.draw();
            }
            if (options._debug) { 
                log("Time taken to highlight:", (new Date()).getTime() - start.getTime(), "ms");
            }
        };
        plot.highlightSeries = highlightSeries;

        function unHighlightSeries(series) {
            var
                seriesAndIndex = getSeriesAndIndex(series)
                , options = plot.getOptions().highlightSeries;

            seriesAndIndex[1].color = originalColors[seriesAndIndex[0]];

            if (options._debug) { var start = new Date(); }
            if (options._optimized) {
                delete highlightedSeries[seriesAndIndex[0]];
                if (plot.drawOverlay && options._debug) {
                    plot.drawOverlay();
                }
                else {
                    plot.triggerRedrawOverlay();
                }
            }
            else {
                plot.draw();
            }
            if (options._debug) { 
                log("Time taken to un-highlight:", (new Date()).getTime() - start.getTime(), "ms");
            }
        };
        plot.unHighlightSeries = unHighlightSeries;

        plot.hooks.bindEvents.push(function (plot, eventHolder) {
            if (!plot.getOptions().highlightSeries.autoHighlight) {
                return;
            }

            var lastHighlighted = null;
            plot.getPlaceholder().bind("plothover", function (evt, pos, item) {
                if (item && lastHighlighted !== item.series) {
                    for(var seriesIndex in highlightedSeries) {
                        delete highlightedSeries[seriesIndex];
                    }
                    if (lastHighlighted) {
                        unHighlightSeries(lastHighlighted);
                    }
                    lastHighlighted = item.series;
                    highlightSeries(item.series);
                }
                else if (!item && lastHighlighted) {
                    unHighlightSeries(lastHighlighted);
                    lastHighlighted = null;
                }
            });
        });

        function getSeriesAndIndex(series) {
            var allPlotSeries = plot.getData();
            if (typeof series == "number") {
                return [series, allPlotSeries[series]];
            }
            else {
                for (var ii = 0; ii < allPlotSeries.length; ii++) {
                    var plotSeries = allPlotSeries[ii];
                    if (
                        plotSeries === series
                        || plotSeries.label === series
                        || plotSeries.label === series.label
                    ) {
                        return [ii, plotSeries];
                    }
                }
            }
        }

        plot.hooks.drawOverlay.push(function (plot, ctx) {
            for(var seriesIndex in highlightedSeries) {
                plot.drawSeries(highlightedSeries[seriesIndex], ctx);
            }
        });
    }

    $.plot.plugins.push({
        init: init,
        options: options,
        name: "highlightSeries",
        version: "1.0"
    });
})(jQuery);
...