Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3284 vikas 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
Selection support is enabled 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
(if you need to change the color later on, you can get to it with
16
plot.getOptions().selection.color).
17
 
18
When selection support is enabled, a "plotselected" event will be
19
emitted on the DOM element you passed into the plot function. The
20
event handler gets a parameter with the ranges selected on the axes,
21
like this:
22
 
23
  placeholder.bind("plotselected", function(event, ranges) {
24
    alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
25
    // similar for yaxis - with multiple axes, the extra ones are in
26
    // x2axis, x3axis, ...
27
  });
28
 
29
The "plotselected" event is only fired when the user has finished
30
making the selection. A "plotselecting" event is fired during the
31
process with the same parameters as the "plotselected" event, in case
32
you want to know what's happening while it's happening,
33
 
34
A "plotunselected" event with no arguments is emitted when the user
35
clicks the mouse to remove the selection.
36
 
37
The plugin allso adds the following methods to the plot object:
38
 
39
- setSelection(ranges, preventEvent)
40
 
41
  Set the selection rectangle. The passed in ranges is on the same
42
  form as returned in the "plotselected" event. If the selection mode
43
  is "x", you should put in either an xaxis range, if the mode is "y"
44
  you need to put in an yaxis range and both xaxis and yaxis if the
45
  selection mode is "xy", like this:
46
 
47
    setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
48
 
49
  setSelection will trigger the "plotselected" event when called. If
50
  you don't want that to happen, e.g. if you're inside a
51
  "plotselected" handler, pass true as the second parameter. If you
52
  are using multiple axes, you can specify the ranges on any of those,
53
  e.g. as x2axis/x3axis/... instead of xaxis, the plugin picks the
54
  first one it sees.
55
 
56
- clearSelection(preventEvent)
57
 
58
  Clear the selection rectangle. Pass in true to avoid getting a
59
  "plotunselected" event.
60
 
61
- getSelection()
62
 
63
  Returns the current selection in the same format as the
64
  "plotselected" event. If there's currently no selection, the
65
  function returns null.
66
 
67
*/
68
 
69
(function ($) {
70
    function init(plot) {
71
        var selection = {
72
                first: { x: -1, y: -1}, second: { x: -1, y: -1},
73
                show: false,
74
                active: false
75
            };
76
 
77
        // FIXME: The drag handling implemented here should be
78
        // abstracted out, there's some similar code from a library in
79
        // the navigation plugin, this should be massaged a bit to fit
80
        // the Flot cases here better and reused. Doing this would
81
        // make this plugin much slimmer.
82
        var savedhandlers = {};
83
 
84
        var mouseUpHandler = null;
85
 
86
        function onMouseMove(e) {
87
            if (selection.active) {
88
                updateSelection(e);
89
 
90
                plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
91
            }
92
        }
93
 
94
        function onMouseDown(e) {
95
            if (e.which != 1)  // only accept left-click
96
                return;
97
 
98
            // cancel out any text selections
99
            document.body.focus();
100
 
101
            // prevent text selection and drag in old-school browsers
102
            if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) {
103
                savedhandlers.onselectstart = document.onselectstart;
104
                document.onselectstart = function () { return false; };
105
            }
106
            if (document.ondrag !== undefined && savedhandlers.ondrag == null) {
107
                savedhandlers.ondrag = document.ondrag;
108
                document.ondrag = function () { return false; };
109
            }
110
 
111
            setSelectionPos(selection.first, e);
112
 
113
            selection.active = true;
114
 
115
            // this is a bit silly, but we have to use a closure to be
116
            // able to whack the same handler again
117
            mouseUpHandler = function (e) { onMouseUp(e); };
118
 
119
            $(document).one("mouseup", mouseUpHandler);
120
        }
121
 
122
        function onMouseUp(e) {
123
            mouseUpHandler = null;
124
 
125
            // revert drag stuff for old-school browsers
126
            if (document.onselectstart !== undefined)
127
                document.onselectstart = savedhandlers.onselectstart;
128
            if (document.ondrag !== undefined)
129
                document.ondrag = savedhandlers.ondrag;
130
 
131
            // no more dragging
132
            selection.active = false;
133
            updateSelection(e);
134
 
135
            if (selectionIsSane())
136
                triggerSelectedEvent();
137
            else {
138
                // this counts as a clear
139
                plot.getPlaceholder().trigger("plotunselected", [ ]);
140
                plot.getPlaceholder().trigger("plotselecting", [ null ]);
141
            }
142
 
143
            return false;
144
        }
145
 
146
        function getSelection() {
147
            if (!selectionIsSane())
148
                return null;
149
 
150
            var r = {}, c1 = selection.first, c2 = selection.second;
151
            $.each(plot.getAxes(), function (name, axis) {
152
                if (axis.used) {
153
                    var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]); 
154
                    r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) };
155
                }
156
            });
157
            return r;
158
        }
159
 
160
        function triggerSelectedEvent() {
161
            var r = getSelection();
162
 
163
            plot.getPlaceholder().trigger("plotselected", [ r ]);
164
 
165
            // backwards-compat stuff, to be removed in future
166
            if (r.xaxis && r.yaxis)
167
                plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
168
        }
169
 
170
        function clamp(min, value, max) {
171
            return value < min ? min: (value > max ? max: value);
172
        }
173
 
174
        function setSelectionPos(pos, e) {
175
            var o = plot.getOptions();
176
            var offset = plot.getPlaceholder().offset();
177
            var plotOffset = plot.getPlotOffset();
178
            pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());
179
            pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
180
 
181
            if (o.selection.mode == "y")
182
                pos.x = pos == selection.first ? 0 : plot.width();
183
 
184
            if (o.selection.mode == "x")
185
                pos.y = pos == selection.first ? 0 : plot.height();
186
        }
187
 
188
        function updateSelection(pos) {
189
            if (pos.pageX == null)
190
                return;
191
 
192
            setSelectionPos(selection.second, pos);
193
            if (selectionIsSane()) {
194
                selection.show = true;
195
                plot.triggerRedrawOverlay();
196
            }
197
            else
198
                clearSelection(true);
199
        }
200
 
201
        function clearSelection(preventEvent) {
202
            if (selection.show) {
203
                selection.show = false;
204
                plot.triggerRedrawOverlay();
205
                if (!preventEvent)
206
                    plot.getPlaceholder().trigger("plotunselected", [ ]);
207
            }
208
        }
209
 
210
        // function taken from markings support in Flot
211
        function extractRange(ranges, coord) {
212
            var axis, from, to, key, axes = plot.getAxes();
213
 
214
            for (var k in axes) {
215
                axis = axes[k];
216
                if (axis.direction == coord) {
217
                    key = coord + axis.n + "axis";
218
                    if (!ranges[key] && axis.n == 1)
219
                        key = coord + "axis"; // support x1axis as xaxis
220
                    if (ranges[key]) {
221
                        from = ranges[key].from;
222
                        to = ranges[key].to;
223
                        break;
224
                    }
225
                }
226
            }
227
 
228
            // backwards-compat stuff - to be removed in future
229
            if (!ranges[key]) {
230
                axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
231
                from = ranges[coord + "1"];
232
                to = ranges[coord + "2"];
233
            }
234
 
235
            // auto-reverse as an added bonus
236
            if (from != null && to != null && from > to) {
237
                var tmp = from;
238
                from = to;
239
                to = tmp;
240
            }
241
 
242
            return { from: from, to: to, axis: axis };
243
        }
244
 
245
        function setSelection(ranges, preventEvent) {
246
            var axis, range, o = plot.getOptions();
247
 
248
            if (o.selection.mode == "y") {
249
                selection.first.x = 0;
250
                selection.second.x = plot.width();
251
            }
252
            else {
253
                range = extractRange(ranges, "x");
254
 
255
                selection.first.x = range.axis.p2c(range.from);
256
                selection.second.x = range.axis.p2c(range.to);
257
            }
258
 
259
            if (o.selection.mode == "x") {
260
                selection.first.y = 0;
261
                selection.second.y = plot.height();
262
            }
263
            else {
264
                range = extractRange(ranges, "y");
265
 
266
                selection.first.y = range.axis.p2c(range.from);
267
                selection.second.y = range.axis.p2c(range.to);
268
            }
269
 
270
            selection.show = true;
271
            plot.triggerRedrawOverlay();
272
            if (!preventEvent && selectionIsSane())
273
                triggerSelectedEvent();
274
        }
275
 
276
        function selectionIsSane() {
277
            var minSize = 5;
278
            return Math.abs(selection.second.x - selection.first.x) >= minSize &&
279
                Math.abs(selection.second.y - selection.first.y) >= minSize;
280
        }
281
 
282
        plot.clearSelection = clearSelection;
283
        plot.setSelection = setSelection;
284
        plot.getSelection = getSelection;
285
 
286
        plot.hooks.bindEvents.push(function(plot, eventHolder) {
287
            var o = plot.getOptions();
288
            if (o.selection.mode != null) {
289
                eventHolder.mousemove(onMouseMove);
290
                eventHolder.mousedown(onMouseDown);
291
            }
292
        });
293
 
294
 
295
        plot.hooks.drawOverlay.push(function (plot, ctx) {
296
            // draw selection
297
            if (selection.show && selectionIsSane()) {
298
                var plotOffset = plot.getPlotOffset();
299
                var o = plot.getOptions();
300
 
301
                ctx.save();
302
                ctx.translate(plotOffset.left, plotOffset.top);
303
 
304
                var c = $.color.parse(o.selection.color);
305
 
306
                ctx.strokeStyle = c.scale('a', 0.8).toString();
307
                ctx.lineWidth = 1;
308
                ctx.lineJoin = "round";
309
                ctx.fillStyle = c.scale('a', 0.4).toString();
310
 
311
                var x = Math.min(selection.first.x, selection.second.x),
312
                    y = Math.min(selection.first.y, selection.second.y),
313
                    w = Math.abs(selection.second.x - selection.first.x),
314
                    h = Math.abs(selection.second.y - selection.first.y);
315
 
316
                ctx.fillRect(x, y, w, h);
317
                ctx.strokeRect(x, y, w, h);
318
 
319
                ctx.restore();
320
            }
321
        });
322
 
323
        plot.hooks.shutdown.push(function (plot, eventHolder) {
324
            eventHolder.unbind("mousemove", onMouseMove);
325
            eventHolder.unbind("mousedown", onMouseDown);
326
 
327
            if (mouseUpHandler)
328
                $(document).unbind("mouseup", mouseUpHandler);
329
        });
330
 
331
    }
332
 
333
    $.plot.plugins.push({
334
        init: init,
335
        options: {
336
            selection: {
337
                mode: null, // one of null, "x", "y" or "xy"
338
                color: "#e8cfac"
339
            }
340
        },
341
        name: 'selection',
342
        version: '1.1'
343
    });
344
})(jQuery);