prometheus

Форк
0
/
jquery.flot.selection.js 
408 строк · 13.4 Кб
1
/*
2
SPDX-License-Identifier: MIT
3
Source: https://github.com/grafana/grafana/blob/main/public/vendor/flot/jquery.flot.selection.js
4
*/
5

6
/* eslint-disable prefer-spread */
7
/* eslint-disable no-loop-func */
8
/* eslint-disable @typescript-eslint/no-this-alias */
9
/* eslint-disable no-redeclare */
10
/* eslint-disable no-useless-escape */
11
/* eslint-disable prefer-const */
12
/* eslint-disable @typescript-eslint/explicit-function-return-type */
13
/* eslint-disable @typescript-eslint/no-use-before-define */
14
/* eslint-disable eqeqeq */
15
/* eslint-disable no-var */
16
/* Flot plugin for selecting regions of a plot.
17

18
Copyright (c) 2007-2013 IOLA and Ole Laursen.
19
Licensed under the MIT license.
20

21
The plugin supports these options:
22

23
selection: {
24
	mode: null or "x" or "y" or "xy",
25
	color: color,
26
	shape: "round" or "miter" or "bevel",
27
	minSize: number of pixels
28
}
29

30
Selection support is enabled by setting the mode to one of "x", "y" or "xy".
31
In "x" mode, the user will only be able to specify the x range, similarly for
32
"y" mode. For "xy", the selection becomes a rectangle where both ranges can be
33
specified. "color" is color of the selection (if you need to change the color
34
later on, you can get to it with plot.getOptions().selection.color). "shape"
35
is the shape of the corners of the selection.
36

37
"minSize" is the minimum size a selection can be in pixels. This value can
38
be customized to determine the smallest size a selection can be and still
39
have the selection rectangle be displayed. When customizing this value, the
40
fact that it refers to pixels, not axis units must be taken into account.
41
Thus, for example, if there is a bar graph in time mode with BarWidth set to 1
42
minute, setting "minSize" to 1 will not make the minimum selection size 1
43
minute, but rather 1 pixel. Note also that setting "minSize" to 0 will prevent
44
"plotunselected" events from being fired when the user clicks the mouse without
45
dragging.
46

47
When selection support is enabled, a "plotselected" event will be emitted on
48
the DOM element you passed into the plot function. The event handler gets a
49
parameter with the ranges selected on the axes, like this:
50

51
	placeholder.bind( "plotselected", function( event, ranges ) {
52
		alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
53
		// similar for yaxis - with multiple axes, the extra ones are in
54
		// x2axis, x3axis, ...
55
	});
56

57
The "plotselected" event is only fired when the user has finished making the
58
selection. A "plotselecting" event is fired during the process with the same
59
parameters as the "plotselected" event, in case you want to know what's
60
happening while it's happening,
61

62
A "plotunselected" event with no arguments is emitted when the user clicks the
63
mouse to remove the selection. As stated above, setting "minSize" to 0 will
64
destroy this behavior.
65

66
The plugin allso adds the following methods to the plot object:
67

68
- setSelection( ranges, preventEvent )
69

70
  Set the selection rectangle. The passed in ranges is on the same form as
71
  returned in the "plotselected" event. If the selection mode is "x", you
72
  should put in either an xaxis range, if the mode is "y" you need to put in
73
  an yaxis range and both xaxis and yaxis if the selection mode is "xy", like
74
  this:
75

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

78
  setSelection will trigger the "plotselected" event when called. If you don't
79
  want that to happen, e.g. if you're inside a "plotselected" handler, pass
80
  true as the second parameter. If you are using multiple axes, you can
81
  specify the ranges on any of those, e.g. as x2axis/x3axis/... instead of
82
  xaxis, the plugin picks the first one it sees.
83

84
- clearSelection( preventEvent )
85

86
  Clear the selection rectangle. Pass in true to avoid getting a
87
  "plotunselected" event.
88

89
- getSelection()
90

91
  Returns the current selection in the same format as the "plotselected"
92
  event. If there's currently no selection, the function returns null.
93

94
*/
95

96
(function($) {
97
  function init(plot) {
98
    var selection = {
99
      first: { x: -1, y: -1 },
100
      second: { x: -1, y: -1 },
101
      show: false,
102
      active: false,
103
    };
104

105
    // FIXME: The drag handling implemented here should be
106
    // abstracted out, there's some similar code from a library in
107
    // the navigation plugin, this should be massaged a bit to fit
108
    // the Flot cases here better and reused. Doing this would
109
    // make this plugin much slimmer.
110
    var savedhandlers = {};
111

112
    var mouseUpHandler = null;
113

114
    function onMouseMove(e) {
115
      if (selection.active) {
116
        updateSelection(e);
117

118
        plot.getPlaceholder().trigger('plotselecting', [getSelection()]);
119
      }
120
    }
121

122
    function onMouseDown(e) {
123
      if (e.which != 1)
124
        // only accept left-click
125
        return;
126

127
      // cancel out any text selections
128
      document.body.focus();
129

130
      // prevent text selection and drag in old-school browsers
131
      if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) {
132
        savedhandlers.onselectstart = document.onselectstart;
133
        document.onselectstart = function() {
134
          return false;
135
        };
136
      }
137
      if (document.ondrag !== undefined && savedhandlers.ondrag == null) {
138
        savedhandlers.ondrag = document.ondrag;
139
        document.ondrag = function() {
140
          return false;
141
        };
142
      }
143

144
      setSelectionPos(selection.first, e);
145

146
      selection.active = true;
147

148
      // this is a bit silly, but we have to use a closure to be
149
      // able to whack the same handler again
150
      mouseUpHandler = function(e) {
151
        onMouseUp(e);
152
      };
153

154
      $(document).one('mouseup', mouseUpHandler);
155
    }
156

157
    function onMouseUp(e) {
158
      mouseUpHandler = null;
159

160
      // revert drag stuff for old-school browsers
161
      if (document.onselectstart !== undefined) document.onselectstart = savedhandlers.onselectstart;
162
      if (document.ondrag !== undefined) document.ondrag = savedhandlers.ondrag;
163

164
      // no more dragging
165
      selection.active = false;
166
      updateSelection(e);
167

168
      if (selectionIsSane()) triggerSelectedEvent(e);
169
      else {
170
        // this counts as a clear
171
        plot.getPlaceholder().trigger('plotunselected', []);
172
        plot.getPlaceholder().trigger('plotselecting', [null]);
173
      }
174

175
      setTimeout(function() {
176
        plot.isSelecting = false;
177
      }, 10);
178

179
      return false;
180
    }
181

182
    function getSelection() {
183
      if (!selectionIsSane()) return null;
184

185
      if (!selection.show) return null;
186

187
      var r = {},
188
        c1 = selection.first,
189
        c2 = selection.second;
190
      var axes = plot.getAxes();
191
      // look if no axis is used
192
      var noAxisInUse = true;
193
      $.each(axes, function(name, axis) {
194
        if (axis.used) {
195
          //anyUsed = false;
196
        }
197
      });
198

199
      $.each(axes, function(name, axis) {
200
        if (axis.used || noAxisInUse) {
201
          var p1 = axis.c2p(c1[axis.direction]),
202
            p2 = axis.c2p(c2[axis.direction]);
203
          r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) };
204
        }
205
      });
206
      return r;
207
    }
208

209
    function triggerSelectedEvent(event) {
210
      var r = getSelection();
211

212
      // Add ctrlKey and metaKey to event
213
      r.ctrlKey = event.ctrlKey;
214
      r.metaKey = event.metaKey;
215

216
      plot.getPlaceholder().trigger('plotselected', [r]);
217

218
      // backwards-compat stuff, to be removed in future
219
      if (r.xaxis && r.yaxis)
220
        plot.getPlaceholder().trigger('selected', [{ x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to }]);
221
    }
222

223
    function clamp(min, value, max) {
224
      return value < min ? min : value > max ? max : value;
225
    }
226

227
    function setSelectionPos(pos, e) {
228
      var o = plot.getOptions();
229
      var offset = plot.getPlaceholder().offset();
230
      var plotOffset = plot.getPlotOffset();
231
      pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());
232
      pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
233

234
      if (o.selection.mode == 'y') pos.x = pos == selection.first ? 0 : plot.width();
235

236
      if (o.selection.mode == 'x') pos.y = pos == selection.first ? 0 : plot.height();
237
    }
238

239
    function updateSelection(pos) {
240
      if (pos.pageX == null) return;
241

242
      setSelectionPos(selection.second, pos);
243
      if (selectionIsSane()) {
244
        plot.isSelecting = true;
245
        selection.show = true;
246
        plot.triggerRedrawOverlay();
247
      } else clearSelection(true);
248
    }
249

250
    function clearSelection(preventEvent) {
251
      if (selection.show) {
252
        selection.show = false;
253
        plot.triggerRedrawOverlay();
254
        if (!preventEvent) plot.getPlaceholder().trigger('plotunselected', []);
255
      }
256
    }
257

258
    // function taken from markings support in Flot
259
    function extractRange(ranges, coord) {
260
      var axis,
261
        from,
262
        to,
263
        key,
264
        axes = plot.getAxes();
265

266
      for (var k in axes) {
267
        axis = axes[k];
268
        if (axis.direction == coord) {
269
          key = coord + axis.n + 'axis';
270
          if (!ranges[key] && axis.n == 1) key = coord + 'axis'; // support x1axis as xaxis
271
          if (ranges[key]) {
272
            from = ranges[key].from;
273
            to = ranges[key].to;
274
            break;
275
          }
276
        }
277
      }
278

279
      // backwards-compat stuff - to be removed in future
280
      if (!ranges[key]) {
281
        axis = coord == 'x' ? plot.getXAxes()[0] : plot.getYAxes()[0];
282
        from = ranges[coord + '1'];
283
        to = ranges[coord + '2'];
284
      }
285

286
      // auto-reverse as an added bonus
287
      if (from != null && to != null && from > to) {
288
        var tmp = from;
289
        from = to;
290
        to = tmp;
291
      }
292

293
      return { from: from, to: to, axis: axis };
294
    }
295

296
    function setSelection(ranges, preventEvent) {
297
      var range,
298
        o = plot.getOptions();
299

300
      if (o.selection.mode == 'y') {
301
        selection.first.x = 0;
302
        selection.second.x = plot.width();
303
      } else {
304
        range = extractRange(ranges, 'x');
305

306
        selection.first.x = range.axis.p2c(range.from);
307
        selection.second.x = range.axis.p2c(range.to);
308
      }
309

310
      if (o.selection.mode == 'x') {
311
        selection.first.y = 0;
312
        selection.second.y = plot.height();
313
      } else {
314
        range = extractRange(ranges, 'y');
315

316
        selection.first.y = range.axis.p2c(range.from);
317
        selection.second.y = range.axis.p2c(range.to);
318
      }
319

320
      selection.show = true;
321
      plot.triggerRedrawOverlay();
322
      if (!preventEvent && selectionIsSane()) triggerSelectedEvent();
323
    }
324

325
    function selectionIsSane() {
326
      var minSize = plot.getOptions().selection.minSize;
327
      return (
328
        Math.abs(selection.second.x - selection.first.x) >= minSize &&
329
        Math.abs(selection.second.y - selection.first.y) >= minSize
330
      );
331
    }
332

333
    plot.clearSelection = clearSelection;
334
    plot.setSelection = setSelection;
335
    plot.getSelection = getSelection;
336

337
    plot.hooks.bindEvents.push(function(plot, eventHolder) {
338
      var o = plot.getOptions();
339
      if (o.selection.mode != null) {
340
        eventHolder.mousemove(onMouseMove);
341
        eventHolder.mousedown(onMouseDown);
342
      }
343
    });
344

345
    plot.hooks.drawOverlay.push(function(plot, ctx) {
346
      // draw selection
347
      if (selection.show && selectionIsSane()) {
348
        var plotOffset = plot.getPlotOffset();
349
        var o = plot.getOptions();
350

351
        ctx.save();
352
        ctx.translate(plotOffset.left, plotOffset.top);
353

354
        var c = $.color.parse(o.selection.color);
355

356
        ctx.strokeStyle = c.scale('a', 0.8).toString();
357
        ctx.lineWidth = 1;
358
        ctx.lineJoin = o.selection.shape;
359
        ctx.fillStyle = c.scale('a', 0.4).toString();
360

361
        var x = Math.min(selection.first.x, selection.second.x) + 0.5,
362
          y = Math.min(selection.first.y, selection.second.y) + 0.5,
363
          w = Math.abs(selection.second.x - selection.first.x) - 1,
364
          h = Math.abs(selection.second.y - selection.first.y) - 1;
365

366
        ctx.fillRect(x, y, w, h);
367
        ctx.strokeRect(x, y, w, h);
368

369
        ctx.restore();
370
      }
371
    });
372

373
    plot.hooks.shutdown.push(function(plot, eventHolder) {
374
      eventHolder.unbind('mousemove', onMouseMove);
375
      eventHolder.unbind('mousedown', onMouseDown);
376

377
      if (mouseUpHandler) {
378
        $(document).unbind('mouseup', mouseUpHandler);
379
        // grafana addition
380
        // In L114 this plugin is overrinding document.onselectstart handler to prevent default or custom behaviour
381
        // Then this patch is being restored during mouseup event. But, mouseup handler is unbound when this plugin is destroyed
382
        // and the overridden onselectstart handler is not restored.  The problematic behaviour surfaces when flot is re-rendered
383
        // as a consequence of panel's model update. When i.e. options are applied via onBlur
384
        // event on some input which results in flot re-render. The mouseup handler should be called to resture the original handlers
385
        //  but by the time the document mouseup event occurs, the event handler is no longer there, so onselectstart is permanently overridden.
386
        // To fix that we are making sure that the overrides are reverted when this plugin is destroyed, the same way as they would
387
        // via mouseup event handler (L138)
388

389
        if (document.onselectstart !== undefined) document.onselectstart = savedhandlers.onselectstart;
390
        if (document.ondrag !== undefined) document.ondrag = savedhandlers.ondrag;
391
      }
392
    });
393
  }
394

395
  $.plot.plugins.push({
396
    init: init,
397
    options: {
398
      selection: {
399
        mode: null, // one of null, "x", "y" or "xy"
400
        color: '#e8cfac',
401
        shape: 'round', // one of "round", "miter", or "bevel"
402
        minSize: 5, // minimum number of pixels
403
      },
404
    },
405
    name: 'selection',
406
    version: '1.1',
407
  });
408
})(window.jQuery);
409

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.