Statistics
| Revision:

root / hci / trunk / eneraptor-web-app / web-app / js / flot / jquery.flot.selection.js @ 11

History | View | Annotate | Download (10.6 KB)

1
/*
2
Flot plugin for selecting regions.
3

4
The plugin defines the following options:
5

6
  selection: {
7
    mode: null or "x" or "y" or "xy",
8
    color: color
9
  }
10

11
You enable selection support by setting the mode to one of "x", "y" or
12
"xy". In "x" mode, the user will only be able to specify the x range,
13
similarly for "y" mode. For "xy", the selection becomes a rectangle
14
where both ranges can be specified. "color" is color of the selection.
15

16
When selection support is enabled, a "plotselected" event will be emitted
17
on the DOM element you passed into the plot function. The event
18
handler gets one extra parameter with the ranges selected on the axes,
19
like this:
20

21
  placeholder.bind("plotselected", function(event, ranges) {
22
    alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
23
    // similar for yaxis, secondary axes are in x2axis
24
    // and y2axis if present
25
  });
26

27
The "plotselected" event is only fired when the user has finished
28
making the selection. A "plotselecting" event is fired during the
29
process with the same parameters as the "plotselected" event, in case
30
you want to know what's happening while it's happening,
31

32
A "plotunselected" event with no arguments is emitted when the user
33
clicks the mouse to remove the selection.
34

35
The plugin allso adds the following methods to the plot object:
36

37
- setSelection(ranges, preventEvent)
38

39
  Set the selection rectangle. The passed in ranges is on the same
40
  form as returned in the "plotselected" event. If the selection
41
  mode is "x", you should put in either an xaxis (or x2axis) object,
42
  if the mode is "y" you need to put in an yaxis (or y2axis) object
43
  and both xaxis/x2axis and yaxis/y2axis if the selection mode is
44
  "xy", like this:
45

46
    setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
47

48
  setSelection will trigger the "plotselected" event when called. If
49
  you don't want that to happen, e.g. if you're inside a
50
  "plotselected" handler, pass true as the second parameter.
51
  
52
- clearSelection(preventEvent)
53

54
  Clear the selection rectangle. Pass in true to avoid getting a
55
  "plotunselected" event.
56

57
- getSelection()
58

59
  Returns the current selection in the same format as the
60
  "plotselected" event. If there's currently no selection, the
61
  function returns null.
62

63
*/
64

    
65
(function ($) {
66
    function init(plot) {
67
        var selection = {
68
                first: { x: -1, y: -1}, second: { x: -1, y: -1},
69
                show: false,
70
                active: false
71
            };
72

    
73
        // FIXME: The drag handling implemented here should be
74
        // abstracted out, there's some similar code from a library in
75
        // the navigation plugin, this should be massaged a bit to fit
76
        // the Flot cases here better and reused. Doing this would
77
        // make this plugin much slimmer.
78
        var savedhandlers = {};
79

    
80
        function onMouseMove(e) {
81
            if (selection.active) {
82
                plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
83

    
84
                updateSelection(e);
85
            }
86
        }
87

    
88
        function onMouseDown(e) {
89
            if (e.which != 1)  // only accept left-click
90
                return;
91
            
92
            // cancel out any text selections
93
            document.body.focus();
94

    
95
            // prevent text selection and drag in old-school browsers
96
            if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) {
97
                savedhandlers.onselectstart = document.onselectstart;
98
                document.onselectstart = function () { return false; };
99
            }
100
            if (document.ondrag !== undefined && savedhandlers.ondrag == null) {
101
                savedhandlers.ondrag = document.ondrag;
102
                document.ondrag = function () { return false; };
103
            }
104

    
105
            setSelectionPos(selection.first, e);
106

    
107
            selection.active = true;
108
            
109
            $(document).one("mouseup", onMouseUp);
110
        }
111

    
112
        function onMouseUp(e) {
113
            // revert drag stuff for old-school browsers
114
            if (document.onselectstart !== undefined)
115
                document.onselectstart = savedhandlers.onselectstart;
116
            if (document.ondrag !== undefined)
117
                document.ondrag = savedhandlers.ondrag;
118

    
119
            // no more draggy-dee-drag
120
            selection.active = false;
121
            updateSelection(e);
122

    
123
            if (selectionIsSane())
124
                triggerSelectedEvent();
125
            else {
126
                // this counts as a clear
127
                plot.getPlaceholder().trigger("plotunselected", [ ]);
128
                plot.getPlaceholder().trigger("plotselecting", [ null ]);
129
            }
130

    
131
            return false;
132
        }
133

    
134
        function getSelection() {
135
            if (!selectionIsSane())
136
                return null;
137

    
138
            var x1 = Math.min(selection.first.x, selection.second.x),
139
                x2 = Math.max(selection.first.x, selection.second.x),
140
                y1 = Math.max(selection.first.y, selection.second.y),
141
                y2 = Math.min(selection.first.y, selection.second.y);
142

    
143
            var r = {};
144
            var axes = plot.getAxes();
145
            if (axes.xaxis.used)
146
                r.xaxis = { from: axes.xaxis.c2p(x1), to: axes.xaxis.c2p(x2) };
147
            if (axes.x2axis.used)
148
                r.x2axis = { from: axes.x2axis.c2p(x1), to: axes.x2axis.c2p(x2) };
149
            if (axes.yaxis.used)
150
                r.yaxis = { from: axes.yaxis.c2p(y1), to: axes.yaxis.c2p(y2) };
151
            if (axes.y2axis.used)
152
                r.y2axis = { from: axes.y2axis.c2p(y1), to: axes.y2axis.c2p(y2) };
153
            return r;
154
        }
155

    
156
        function triggerSelectedEvent() {
157
            var r = getSelection();
158

    
159
            plot.getPlaceholder().trigger("plotselected", [ r ]);
160

    
161
            // backwards-compat stuff, to be removed in future
162
            var axes = plot.getAxes();
163
            if (axes.xaxis.used && axes.yaxis.used)
164
                plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
165
        }
166

    
167
        function clamp(min, value, max) {
168
            return value < min? min: (value > max? max: value);
169
        }
170

    
171
        function setSelectionPos(pos, e) {
172
            var o = plot.getOptions();
173
            var offset = plot.getPlaceholder().offset();
174
            var plotOffset = plot.getPlotOffset();
175
            pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());
176
            pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
177

    
178
            if (o.selection.mode == "y")
179
                pos.x = pos == selection.first? 0: plot.width();
180

    
181
            if (o.selection.mode == "x")
182
                pos.y = pos == selection.first? 0: plot.height();
183
        }
184

    
185
        function updateSelection(pos) {
186
            if (pos.pageX == null)
187
                return;
188

    
189
            setSelectionPos(selection.second, pos);
190
            if (selectionIsSane()) {
191
                selection.show = true;
192
                plot.triggerRedrawOverlay();
193
            }
194
            else
195
                clearSelection(true);
196
        }
197

    
198
        function clearSelection(preventEvent) {
199
            if (selection.show) {
200
                selection.show = false;
201
                plot.triggerRedrawOverlay();
202
                if (!preventEvent)
203
                    plot.getPlaceholder().trigger("plotunselected", [ ]);
204
            }
205
        }
206

    
207
        function setSelection(ranges, preventEvent) {
208
            var axis, range, axes = plot.getAxes();
209
            var o = plot.getOptions();
210

    
211
            if (o.selection.mode == "y") {
212
                selection.first.x = 0;
213
                selection.second.x = plot.width();
214
            }
215
            else {
216
                axis = ranges["xaxis"]? axes["xaxis"]: (ranges["x2axis"]? axes["x2axis"]: axes["xaxis"]);
217
                range = ranges["xaxis"] || ranges["x2axis"] || { from:ranges["x1"], to:ranges["x2"] }
218
                selection.first.x = axis.p2c(Math.min(range.from, range.to));
219
                selection.second.x = axis.p2c(Math.max(range.from, range.to));
220
            }
221

    
222
            if (o.selection.mode == "x") {
223
                selection.first.y = 0;
224
                selection.second.y = plot.height();
225
            }
226
            else {
227
                axis = ranges["yaxis"]? axes["yaxis"]: (ranges["y2axis"]? axes["y2axis"]: axes["yaxis"]);
228
                range = ranges["yaxis"] || ranges["y2axis"] || { from:ranges["y1"], to:ranges["y2"] }
229
                selection.first.y = axis.p2c(Math.min(range.from, range.to));
230
                selection.second.y = axis.p2c(Math.max(range.from, range.to));
231
            }
232

    
233
            selection.show = true;
234
            plot.triggerRedrawOverlay();
235
            if (!preventEvent)
236
                triggerSelectedEvent();
237
        }
238

    
239
        function selectionIsSane() {
240
            var minSize = 5;
241
            return Math.abs(selection.second.x - selection.first.x) >= minSize &&
242
                Math.abs(selection.second.y - selection.first.y) >= minSize;
243
        }
244

    
245
        plot.clearSelection = clearSelection;
246
        plot.setSelection = setSelection;
247
        plot.getSelection = getSelection;
248

    
249
        plot.hooks.bindEvents.push(function(plot, eventHolder) {
250
            var o = plot.getOptions();
251
            if (o.selection.mode != null)
252
                eventHolder.mousemove(onMouseMove);
253

    
254
            if (o.selection.mode != null)
255
                eventHolder.mousedown(onMouseDown);
256
        });
257

    
258

    
259
        plot.hooks.drawOverlay.push(function (plot, ctx) {
260
            // draw selection
261
            if (selection.show && selectionIsSane()) {
262
                var plotOffset = plot.getPlotOffset();
263
                var o = plot.getOptions();
264

    
265
                ctx.save();
266
                ctx.translate(plotOffset.left, plotOffset.top);
267

    
268
                var c = $.color.parse(o.selection.color);
269

    
270
                ctx.strokeStyle = c.scale('a', 0.8).toString();
271
                ctx.lineWidth = 1;
272
                ctx.lineJoin = "round";
273
                ctx.fillStyle = c.scale('a', 0.4).toString();
274

    
275
                var x = Math.min(selection.first.x, selection.second.x),
276
                    y = Math.min(selection.first.y, selection.second.y),
277
                    w = Math.abs(selection.second.x - selection.first.x),
278
                    h = Math.abs(selection.second.y - selection.first.y);
279

    
280
                ctx.fillRect(x, y, w, h);
281
                ctx.strokeRect(x, y, w, h);
282

    
283
                ctx.restore();
284
            }
285
        });
286
    }
287

    
288
    $.plot.plugins.push({
289
        init: init,
290
        options: {
291
            selection: {
292
                mode: null, // one of null, "x", "y" or "xy"
293
                color: "#e8cfac"
294
            }
295
        },
296
        name: 'selection',
297
        version: '1.0'
298
    });
299
})(jQuery);