iobroker.ebus 3.2.4 → 3.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.eslintrc.json +34 -34
  2. package/.releaseconfig.json +3 -0
  3. package/LICENSE +20 -20
  4. package/README.md +147 -130
  5. package/admin/index_m.html +419 -419
  6. package/admin/style.css +18 -18
  7. package/admin/words.js +27 -27
  8. package/io-package.json +218 -192
  9. package/lib/support_tools.js +370 -370
  10. package/lib/tools.js +99 -99
  11. package/main.js +1232 -1232
  12. package/package.json +13 -11
  13. package/widgets/ebus/lib/js/flot/jquery.canvaswrapper.js +549 -549
  14. package/widgets/ebus/lib/js/flot/jquery.colorhelpers.js +199 -199
  15. package/widgets/ebus/lib/js/flot/jquery.flot.axislabels.js +212 -212
  16. package/widgets/ebus/lib/js/flot/jquery.flot.browser.js +98 -98
  17. package/widgets/ebus/lib/js/flot/jquery.flot.categories.js +202 -202
  18. package/widgets/ebus/lib/js/flot/jquery.flot.composeImages.js +330 -330
  19. package/widgets/ebus/lib/js/flot/jquery.flot.crosshair.js +202 -202
  20. package/widgets/ebus/lib/js/flot/jquery.flot.drawSeries.js +662 -662
  21. package/widgets/ebus/lib/js/flot/jquery.flot.errorbars.js +375 -375
  22. package/widgets/ebus/lib/js/flot/jquery.flot.fillbetween.js +254 -254
  23. package/widgets/ebus/lib/js/flot/jquery.flot.flatdata.js +47 -47
  24. package/widgets/ebus/lib/js/flot/jquery.flot.hover.js +361 -361
  25. package/widgets/ebus/lib/js/flot/jquery.flot.image.js +249 -249
  26. package/widgets/ebus/lib/js/flot/jquery.flot.js +2953 -2953
  27. package/widgets/ebus/lib/js/flot/jquery.flot.legend.js +437 -437
  28. package/widgets/ebus/lib/js/flot/jquery.flot.logaxis.js +298 -298
  29. package/widgets/ebus/lib/js/flot/jquery.flot.navigate.js +834 -834
  30. package/widgets/ebus/lib/js/flot/jquery.flot.pie.js +794 -794
  31. package/widgets/ebus/lib/js/flot/jquery.flot.resize.js +60 -60
  32. package/widgets/ebus/lib/js/flot/jquery.flot.saturated.js +43 -43
  33. package/widgets/ebus/lib/js/flot/jquery.flot.selection.js +527 -527
  34. package/widgets/ebus/lib/js/flot/jquery.flot.stack.js +220 -220
  35. package/widgets/ebus/lib/js/flot/jquery.flot.symbol.js +98 -98
  36. package/widgets/ebus/lib/js/flot/jquery.flot.threshold.js +143 -143
  37. package/widgets/ebus/lib/js/flot/jquery.flot.time.js +586 -586
  38. package/widgets/ebus/lib/js/flot/jquery.flot.touch.js +320 -320
  39. package/widgets/ebus/lib/js/flot/jquery.flot.touchNavigate.js +360 -360
  40. package/widgets/ebus/lib/js/flot/jquery.flot.uiConstants.js +10 -10
  41. package/widgets/ebus/lib/js/flot/jquery.js +9473 -9473
  42. package/widgets/ebus/lib/js/lib/globalize.culture.en-US.js +33 -33
  43. package/widgets/ebus/lib/js/lib/globalize.js +1601 -1601
  44. package/widgets/ebus/lib/js/lib/jquery.event.drag.js +145 -145
  45. package/widgets/ebus/lib/js/lib/jquery.mousewheel.js +86 -86
  46. package/widgets/ebus.html +2395 -2395
  47. package/readme.txt +0 -297
@@ -1,437 +1,437 @@
1
- /* Flot plugin for drawing legends.
2
-
3
- */
4
-
5
- (function($) {
6
- var defaultOptions = {
7
- legend: {
8
- show: false,
9
- noColumns: 1,
10
- labelFormatter: null, // fn: string -> string
11
- container: null, // container (as jQuery object) to put legend in, null means default on top of graph
12
- position: 'ne', // position of default legend container within plot
13
- margin: 5, // distance from grid edge to default legend container within plot
14
- sorted: null // default to no legend sorting
15
- }
16
- };
17
-
18
- function insertLegend(plot, options, placeholder, legendEntries) {
19
- // clear before redraw
20
- if (options.legend.container != null) {
21
- $(options.legend.container).html('');
22
- } else {
23
- placeholder.find('.legend').remove();
24
- }
25
-
26
- if (!options.legend.show) {
27
- return;
28
- }
29
-
30
- // Save the legend entries in legend options
31
- var entries = options.legend.legendEntries = legendEntries,
32
- plotOffset = options.legend.plotOffset = plot.getPlotOffset(),
33
- html = [],
34
- entry, labelHtml, iconHtml,
35
- j = 0,
36
- i,
37
- pos = "",
38
- p = options.legend.position,
39
- m = options.legend.margin,
40
- shape = {
41
- name: '',
42
- label: '',
43
- xPos: '',
44
- yPos: ''
45
- };
46
-
47
- html[j++] = '<svg class="legendLayer" style="width:inherit;height:inherit;">';
48
- html[j++] = '<rect class="background" width="100%" height="100%"/>';
49
- html[j++] = svgShapeDefs;
50
-
51
- var left = 0;
52
- var columnWidths = [];
53
- var style = window.getComputedStyle(document.querySelector('body'));
54
- for (i = 0; i < entries.length; ++i) {
55
- let columnIndex = i % options.legend.noColumns;
56
- entry = entries[i];
57
- shape.label = entry.label;
58
- var info = plot.getSurface().getTextInfo('', shape.label, {
59
- style: style.fontStyle,
60
- variant: style.fontVariant,
61
- weight: style.fontWeight,
62
- size: parseInt(style.fontSize),
63
- lineHeight: parseInt(style.lineHeight),
64
- family: style.fontFamily
65
- });
66
-
67
- var labelWidth = info.width;
68
- // 36px = 1.5em + 6px margin
69
- var iconWidth = 48;
70
- if (columnWidths[columnIndex]) {
71
- if (labelWidth > columnWidths[columnIndex]) {
72
- columnWidths[columnIndex] = labelWidth + iconWidth;
73
- }
74
- } else {
75
- columnWidths[columnIndex] = labelWidth + iconWidth;
76
- }
77
- }
78
-
79
- // Generate html for icons and labels from a list of entries
80
- for (i = 0; i < entries.length; ++i) {
81
- let columnIndex = i % options.legend.noColumns;
82
- entry = entries[i];
83
- iconHtml = '';
84
- shape.label = entry.label;
85
- shape.xPos = (left + 3) + 'px';
86
- left += columnWidths[columnIndex];
87
- if ((i + 1) % options.legend.noColumns === 0) {
88
- left = 0;
89
- }
90
- shape.yPos = Math.floor(i / options.legend.noColumns) * 1.5 + 'em';
91
- // area
92
- if (entry.options.lines.show && entry.options.lines.fill) {
93
- shape.name = 'area';
94
- shape.fillColor = entry.color;
95
- iconHtml += getEntryIconHtml(shape);
96
- }
97
- // bars
98
- if (entry.options.bars.show) {
99
- shape.name = 'bar';
100
- shape.fillColor = entry.color;
101
- iconHtml += getEntryIconHtml(shape);
102
- }
103
- // lines
104
- if (entry.options.lines.show && !entry.options.lines.fill) {
105
- shape.name = 'line';
106
- shape.strokeColor = entry.color;
107
- shape.strokeWidth = entry.options.lines.lineWidth;
108
- iconHtml += getEntryIconHtml(shape);
109
- }
110
- // points
111
- if (entry.options.points.show) {
112
- shape.name = entry.options.points.symbol;
113
- shape.strokeColor = entry.color;
114
- shape.fillColor = entry.options.points.fillColor;
115
- shape.strokeWidth = entry.options.points.lineWidth;
116
- iconHtml += getEntryIconHtml(shape);
117
- }
118
-
119
- labelHtml = '<text x="' + shape.xPos + '" y="' + shape.yPos + '" text-anchor="start"><tspan dx="2em" dy="1.2em">' + shape.label + '</tspan></text>'
120
- html[j++] = '<g>' + iconHtml + labelHtml + '</g>';
121
- }
122
-
123
- html[j++] = '</svg>';
124
- if (m[0] == null) {
125
- m = [m, m];
126
- }
127
-
128
- if (p.charAt(0) === 'n') {
129
- pos += 'top:' + (m[1] + plotOffset.top) + 'px;';
130
- } else if (p.charAt(0) === 's') {
131
- pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;';
132
- }
133
-
134
- if (p.charAt(1) === 'e') {
135
- pos += 'right:' + (m[0] + plotOffset.right) + 'px;';
136
- } else if (p.charAt(1) === 'w') {
137
- pos += 'left:' + (m[0] + plotOffset.left) + 'px;';
138
- }
139
-
140
- var width = 6;
141
- for (i = 0; i < columnWidths.length; ++i) {
142
- width += columnWidths[i];
143
- }
144
-
145
- var legendEl,
146
- height = Math.ceil(entries.length / options.legend.noColumns) * 1.6;
147
- if (!options.legend.container) {
148
- legendEl = $('<div class="legend" style="position:absolute;' + pos + '">' + html.join('') + '</div>').appendTo(placeholder);
149
- legendEl.css('width', width + 'px');
150
- legendEl.css('height', height + 'em');
151
- legendEl.css('pointerEvents', 'none');
152
- } else {
153
- legendEl = $(html.join('')).appendTo(options.legend.container)[0];
154
- options.legend.container.style.width = width + 'px';
155
- options.legend.container.style.height = height + 'em';
156
- }
157
- }
158
-
159
- // Generate html for a shape
160
- function getEntryIconHtml(shape) {
161
- var html = '',
162
- name = shape.name,
163
- x = shape.xPos,
164
- y = shape.yPos,
165
- fill = shape.fillColor,
166
- stroke = shape.strokeColor,
167
- width = shape.strokeWidth;
168
- switch (name) {
169
- case 'circle':
170
- html = '<use xlink:href="#circle" class="legendIcon" ' +
171
- 'x="' + x + '" ' +
172
- 'y="' + y + '" ' +
173
- 'fill="' + fill + '" ' +
174
- 'stroke="' + stroke + '" ' +
175
- 'stroke-width="' + width + '" ' +
176
- 'width="1.5em" height="1.5em"' +
177
- '/>';
178
- break;
179
- case 'diamond':
180
- html = '<use xlink:href="#diamond" class="legendIcon" ' +
181
- 'x="' + x + '" ' +
182
- 'y="' + y + '" ' +
183
- 'fill="' + fill + '" ' +
184
- 'stroke="' + stroke + '" ' +
185
- 'stroke-width="' + width + '" ' +
186
- 'width="1.5em" height="1.5em"' +
187
- '/>';
188
- break;
189
- case 'cross':
190
- html = '<use xlink:href="#cross" class="legendIcon" ' +
191
- 'x="' + x + '" ' +
192
- 'y="' + y + '" ' +
193
- // 'fill="' + fill + '" ' +
194
- 'stroke="' + stroke + '" ' +
195
- 'stroke-width="' + width + '" ' +
196
- 'width="1.5em" height="1.5em"' +
197
- '/>';
198
- break;
199
- case 'rectangle':
200
- html = '<use xlink:href="#rectangle" class="legendIcon" ' +
201
- 'x="' + x + '" ' +
202
- 'y="' + y + '" ' +
203
- 'fill="' + fill + '" ' +
204
- 'stroke="' + stroke + '" ' +
205
- 'stroke-width="' + width + '" ' +
206
- 'width="1.5em" height="1.5em"' +
207
- '/>';
208
- break;
209
- case 'plus':
210
- html = '<use xlink:href="#plus" class="legendIcon" ' +
211
- 'x="' + x + '" ' +
212
- 'y="' + y + '" ' +
213
- // 'fill="' + fill + '" ' +
214
- 'stroke="' + stroke + '" ' +
215
- 'stroke-width="' + width + '" ' +
216
- 'width="1.5em" height="1.5em"' +
217
- '/>';
218
- break;
219
- case 'bar':
220
- html = '<use xlink:href="#bars" class="legendIcon" ' +
221
- 'x="' + x + '" ' +
222
- 'y="' + y + '" ' +
223
- 'fill="' + fill + '" ' +
224
- // 'stroke="' + stroke + '" ' +
225
- // 'stroke-width="' + width + '" ' +
226
- 'width="1.5em" height="1.5em"' +
227
- '/>';
228
- break;
229
- case 'area':
230
- html = '<use xlink:href="#area" class="legendIcon" ' +
231
- 'x="' + x + '" ' +
232
- 'y="' + y + '" ' +
233
- 'fill="' + fill + '" ' +
234
- // 'stroke="' + stroke + '" ' +
235
- // 'stroke-width="' + width + '" ' +
236
- 'width="1.5em" height="1.5em"' +
237
- '/>';
238
- break;
239
- case 'line':
240
- html = '<use xlink:href="#line" class="legendIcon" ' +
241
- 'x="' + x + '" ' +
242
- 'y="' + y + '" ' +
243
- // 'fill="' + fill + '" ' +
244
- 'stroke="' + stroke + '" ' +
245
- 'stroke-width="' + width + '" ' +
246
- 'width="1.5em" height="1.5em"' +
247
- '/>';
248
- break;
249
- default:
250
- // default is circle
251
- html = '<use xlink:href="#circle" class="legendIcon" ' +
252
- 'x="' + x + '" ' +
253
- 'y="' + y + '" ' +
254
- 'fill="' + fill + '" ' +
255
- 'stroke="' + stroke + '" ' +
256
- 'stroke-width="' + width + '" ' +
257
- 'width="1.5em" height="1.5em"' +
258
- '/>';
259
- }
260
-
261
- return html;
262
- }
263
-
264
- // Define svg symbols for shapes
265
- var svgShapeDefs = '' +
266
- '<defs>' +
267
- '<symbol id="line" fill="none" viewBox="-5 -5 25 25">' +
268
- '<polyline points="0,15 5,5 10,10 15,0"/>' +
269
- '</symbol>' +
270
-
271
- '<symbol id="area" stroke-width="1" viewBox="-5 -5 25 25">' +
272
- '<polyline points="0,15 5,5 10,10 15,0, 15,15, 0,15"/>' +
273
- '</symbol>' +
274
-
275
- '<symbol id="bars" stroke-width="1" viewBox="-5 -5 25 25">' +
276
- '<polyline points="1.5,15.5 1.5,12.5, 4.5,12.5 4.5,15.5 6.5,15.5 6.5,3.5, 9.5,3.5 9.5,15.5 11.5,15.5 11.5,7.5 14.5,7.5 14.5,15.5 1.5,15.5"/>' +
277
- '</symbol>' +
278
-
279
- '<symbol id="circle" viewBox="-5 -5 25 25">' +
280
- '<circle cx="0" cy="15" r="2.5"/>' +
281
- '<circle cx="5" cy="5" r="2.5"/>' +
282
- '<circle cx="10" cy="10" r="2.5"/>' +
283
- '<circle cx="15" cy="0" r="2.5"/>' +
284
- '</symbol>' +
285
-
286
- '<symbol id="rectangle" viewBox="-5 -5 25 25">' +
287
- '<rect x="-2.1" y="12.9" width="4.2" height="4.2"/>' +
288
- '<rect x="2.9" y="2.9" width="4.2" height="4.2"/>' +
289
- '<rect x="7.9" y="7.9" width="4.2" height="4.2"/>' +
290
- '<rect x="12.9" y="-2.1" width="4.2" height="4.2"/>' +
291
- '</symbol>' +
292
-
293
- '<symbol id="diamond" viewBox="-5 -5 25 25">' +
294
- '<path d="M-3,15 L0,12 L3,15, L0,18 Z"/>' +
295
- '<path d="M2,5 L5,2 L8,5, L5,8 Z"/>' +
296
- '<path d="M7,10 L10,7 L13,10, L10,13 Z"/>' +
297
- '<path d="M12,0 L15,-3 L18,0, L15,3 Z"/>' +
298
- '</symbol>' +
299
-
300
- '<symbol id="cross" fill="none" viewBox="-5 -5 25 25">' +
301
- '<path d="M-2.1,12.9 L2.1,17.1, M2.1,12.9 L-2.1,17.1 Z"/>' +
302
- '<path d="M2.9,2.9 L7.1,7.1 M7.1,2.9 L2.9,7.1 Z"/>' +
303
- '<path d="M7.9,7.9 L12.1,12.1 M12.1,7.9 L7.9,12.1 Z"/>' +
304
- '<path d="M12.9,-2.1 L17.1,2.1 M17.1,-2.1 L12.9,2.1 Z"/>' +
305
- '</symbol>' +
306
-
307
- '<symbol id="plus" fill="none" viewBox="-5 -5 25 25">' +
308
- '<path d="M0,12 L0,18, M-3,15 L3,15 Z"/>' +
309
- '<path d="M5,2 L5,8 M2,5 L8,5 Z"/>' +
310
- '<path d="M10,7 L10,13 M7,10 L13,10 Z"/>' +
311
- '<path d="M15,-3 L15,3 M12,0 L18,0 Z"/>' +
312
- '</symbol>' +
313
- '</defs>';
314
-
315
- // Generate a list of legend entries in their final order
316
- function getLegendEntries(series, labelFormatter, sorted) {
317
- var lf = labelFormatter,
318
- legendEntries = series.reduce(function(validEntries, s, i) {
319
- var labelEval = (lf ? lf(s.label, s) : s.label)
320
- if (s.hasOwnProperty("label") ? labelEval : true) {
321
- var entry = {
322
- label: labelEval || 'Plot ' + (i + 1),
323
- color: s.color,
324
- options: {
325
- lines: s.lines,
326
- points: s.points,
327
- bars: s.bars
328
- }
329
- }
330
- validEntries.push(entry)
331
- }
332
- return validEntries;
333
- }, []);
334
-
335
- // Sort the legend using either the default or a custom comparator
336
- if (sorted) {
337
- if ($.isFunction(sorted)) {
338
- legendEntries.sort(sorted);
339
- } else if (sorted === 'reverse') {
340
- legendEntries.reverse();
341
- } else {
342
- var ascending = (sorted !== 'descending');
343
- legendEntries.sort(function(a, b) {
344
- return a.label === b.label
345
- ? 0
346
- : ((a.label < b.label) !== ascending ? 1 : -1 // Logical XOR
347
- );
348
- });
349
- }
350
- }
351
-
352
- return legendEntries;
353
- }
354
-
355
- // return false if opts1 same as opts2
356
- function checkOptions(opts1, opts2) {
357
- for (var prop in opts1) {
358
- if (opts1.hasOwnProperty(prop)) {
359
- if (opts1[prop] !== opts2[prop]) {
360
- return true;
361
- }
362
- }
363
- }
364
- return false;
365
- }
366
-
367
- // Compare two lists of legend entries
368
- function shouldRedraw(oldEntries, newEntries) {
369
- if (!oldEntries || !newEntries) {
370
- return true;
371
- }
372
-
373
- if (oldEntries.length !== newEntries.length) {
374
- return true;
375
- }
376
- var i, newEntry, oldEntry, newOpts, oldOpts;
377
- for (i = 0; i < newEntries.length; i++) {
378
- newEntry = newEntries[i];
379
- oldEntry = oldEntries[i];
380
-
381
- if (newEntry.label !== oldEntry.label) {
382
- return true;
383
- }
384
-
385
- if (newEntry.color !== oldEntry.color) {
386
- return true;
387
- }
388
-
389
- // check for changes in lines options
390
- newOpts = newEntry.options.lines;
391
- oldOpts = oldEntry.options.lines;
392
- if (checkOptions(newOpts, oldOpts)) {
393
- return true;
394
- }
395
-
396
- // check for changes in points options
397
- newOpts = newEntry.options.points;
398
- oldOpts = oldEntry.options.points;
399
- if (checkOptions(newOpts, oldOpts)) {
400
- return true;
401
- }
402
-
403
- // check for changes in bars options
404
- newOpts = newEntry.options.bars;
405
- oldOpts = oldEntry.options.bars;
406
- if (checkOptions(newOpts, oldOpts)) {
407
- return true;
408
- }
409
- }
410
-
411
- return false;
412
- }
413
-
414
- function init(plot) {
415
- plot.hooks.setupGrid.push(function (plot) {
416
- var options = plot.getOptions();
417
- var series = plot.getData(),
418
- labelFormatter = options.legend.labelFormatter,
419
- oldEntries = options.legend.legendEntries,
420
- oldPlotOffset = options.legend.plotOffset,
421
- newEntries = getLegendEntries(series, labelFormatter, options.legend.sorted),
422
- newPlotOffset = plot.getPlotOffset();
423
-
424
- if (shouldRedraw(oldEntries, newEntries) ||
425
- checkOptions(oldPlotOffset, newPlotOffset)) {
426
- insertLegend(plot, options, plot.getPlaceholder(), newEntries);
427
- }
428
- });
429
- }
430
-
431
- $.plot.plugins.push({
432
- init: init,
433
- options: defaultOptions,
434
- name: 'legend',
435
- version: '1.0'
436
- });
437
- })(jQuery);
1
+ /* Flot plugin for drawing legends.
2
+
3
+ */
4
+
5
+ (function($) {
6
+ var defaultOptions = {
7
+ legend: {
8
+ show: false,
9
+ noColumns: 1,
10
+ labelFormatter: null, // fn: string -> string
11
+ container: null, // container (as jQuery object) to put legend in, null means default on top of graph
12
+ position: 'ne', // position of default legend container within plot
13
+ margin: 5, // distance from grid edge to default legend container within plot
14
+ sorted: null // default to no legend sorting
15
+ }
16
+ };
17
+
18
+ function insertLegend(plot, options, placeholder, legendEntries) {
19
+ // clear before redraw
20
+ if (options.legend.container != null) {
21
+ $(options.legend.container).html('');
22
+ } else {
23
+ placeholder.find('.legend').remove();
24
+ }
25
+
26
+ if (!options.legend.show) {
27
+ return;
28
+ }
29
+
30
+ // Save the legend entries in legend options
31
+ var entries = options.legend.legendEntries = legendEntries,
32
+ plotOffset = options.legend.plotOffset = plot.getPlotOffset(),
33
+ html = [],
34
+ entry, labelHtml, iconHtml,
35
+ j = 0,
36
+ i,
37
+ pos = "",
38
+ p = options.legend.position,
39
+ m = options.legend.margin,
40
+ shape = {
41
+ name: '',
42
+ label: '',
43
+ xPos: '',
44
+ yPos: ''
45
+ };
46
+
47
+ html[j++] = '<svg class="legendLayer" style="width:inherit;height:inherit;">';
48
+ html[j++] = '<rect class="background" width="100%" height="100%"/>';
49
+ html[j++] = svgShapeDefs;
50
+
51
+ var left = 0;
52
+ var columnWidths = [];
53
+ var style = window.getComputedStyle(document.querySelector('body'));
54
+ for (i = 0; i < entries.length; ++i) {
55
+ let columnIndex = i % options.legend.noColumns;
56
+ entry = entries[i];
57
+ shape.label = entry.label;
58
+ var info = plot.getSurface().getTextInfo('', shape.label, {
59
+ style: style.fontStyle,
60
+ variant: style.fontVariant,
61
+ weight: style.fontWeight,
62
+ size: parseInt(style.fontSize),
63
+ lineHeight: parseInt(style.lineHeight),
64
+ family: style.fontFamily
65
+ });
66
+
67
+ var labelWidth = info.width;
68
+ // 36px = 1.5em + 6px margin
69
+ var iconWidth = 48;
70
+ if (columnWidths[columnIndex]) {
71
+ if (labelWidth > columnWidths[columnIndex]) {
72
+ columnWidths[columnIndex] = labelWidth + iconWidth;
73
+ }
74
+ } else {
75
+ columnWidths[columnIndex] = labelWidth + iconWidth;
76
+ }
77
+ }
78
+
79
+ // Generate html for icons and labels from a list of entries
80
+ for (i = 0; i < entries.length; ++i) {
81
+ let columnIndex = i % options.legend.noColumns;
82
+ entry = entries[i];
83
+ iconHtml = '';
84
+ shape.label = entry.label;
85
+ shape.xPos = (left + 3) + 'px';
86
+ left += columnWidths[columnIndex];
87
+ if ((i + 1) % options.legend.noColumns === 0) {
88
+ left = 0;
89
+ }
90
+ shape.yPos = Math.floor(i / options.legend.noColumns) * 1.5 + 'em';
91
+ // area
92
+ if (entry.options.lines.show && entry.options.lines.fill) {
93
+ shape.name = 'area';
94
+ shape.fillColor = entry.color;
95
+ iconHtml += getEntryIconHtml(shape);
96
+ }
97
+ // bars
98
+ if (entry.options.bars.show) {
99
+ shape.name = 'bar';
100
+ shape.fillColor = entry.color;
101
+ iconHtml += getEntryIconHtml(shape);
102
+ }
103
+ // lines
104
+ if (entry.options.lines.show && !entry.options.lines.fill) {
105
+ shape.name = 'line';
106
+ shape.strokeColor = entry.color;
107
+ shape.strokeWidth = entry.options.lines.lineWidth;
108
+ iconHtml += getEntryIconHtml(shape);
109
+ }
110
+ // points
111
+ if (entry.options.points.show) {
112
+ shape.name = entry.options.points.symbol;
113
+ shape.strokeColor = entry.color;
114
+ shape.fillColor = entry.options.points.fillColor;
115
+ shape.strokeWidth = entry.options.points.lineWidth;
116
+ iconHtml += getEntryIconHtml(shape);
117
+ }
118
+
119
+ labelHtml = '<text x="' + shape.xPos + '" y="' + shape.yPos + '" text-anchor="start"><tspan dx="2em" dy="1.2em">' + shape.label + '</tspan></text>'
120
+ html[j++] = '<g>' + iconHtml + labelHtml + '</g>';
121
+ }
122
+
123
+ html[j++] = '</svg>';
124
+ if (m[0] == null) {
125
+ m = [m, m];
126
+ }
127
+
128
+ if (p.charAt(0) === 'n') {
129
+ pos += 'top:' + (m[1] + plotOffset.top) + 'px;';
130
+ } else if (p.charAt(0) === 's') {
131
+ pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;';
132
+ }
133
+
134
+ if (p.charAt(1) === 'e') {
135
+ pos += 'right:' + (m[0] + plotOffset.right) + 'px;';
136
+ } else if (p.charAt(1) === 'w') {
137
+ pos += 'left:' + (m[0] + plotOffset.left) + 'px;';
138
+ }
139
+
140
+ var width = 6;
141
+ for (i = 0; i < columnWidths.length; ++i) {
142
+ width += columnWidths[i];
143
+ }
144
+
145
+ var legendEl,
146
+ height = Math.ceil(entries.length / options.legend.noColumns) * 1.6;
147
+ if (!options.legend.container) {
148
+ legendEl = $('<div class="legend" style="position:absolute;' + pos + '">' + html.join('') + '</div>').appendTo(placeholder);
149
+ legendEl.css('width', width + 'px');
150
+ legendEl.css('height', height + 'em');
151
+ legendEl.css('pointerEvents', 'none');
152
+ } else {
153
+ legendEl = $(html.join('')).appendTo(options.legend.container)[0];
154
+ options.legend.container.style.width = width + 'px';
155
+ options.legend.container.style.height = height + 'em';
156
+ }
157
+ }
158
+
159
+ // Generate html for a shape
160
+ function getEntryIconHtml(shape) {
161
+ var html = '',
162
+ name = shape.name,
163
+ x = shape.xPos,
164
+ y = shape.yPos,
165
+ fill = shape.fillColor,
166
+ stroke = shape.strokeColor,
167
+ width = shape.strokeWidth;
168
+ switch (name) {
169
+ case 'circle':
170
+ html = '<use xlink:href="#circle" class="legendIcon" ' +
171
+ 'x="' + x + '" ' +
172
+ 'y="' + y + '" ' +
173
+ 'fill="' + fill + '" ' +
174
+ 'stroke="' + stroke + '" ' +
175
+ 'stroke-width="' + width + '" ' +
176
+ 'width="1.5em" height="1.5em"' +
177
+ '/>';
178
+ break;
179
+ case 'diamond':
180
+ html = '<use xlink:href="#diamond" class="legendIcon" ' +
181
+ 'x="' + x + '" ' +
182
+ 'y="' + y + '" ' +
183
+ 'fill="' + fill + '" ' +
184
+ 'stroke="' + stroke + '" ' +
185
+ 'stroke-width="' + width + '" ' +
186
+ 'width="1.5em" height="1.5em"' +
187
+ '/>';
188
+ break;
189
+ case 'cross':
190
+ html = '<use xlink:href="#cross" class="legendIcon" ' +
191
+ 'x="' + x + '" ' +
192
+ 'y="' + y + '" ' +
193
+ // 'fill="' + fill + '" ' +
194
+ 'stroke="' + stroke + '" ' +
195
+ 'stroke-width="' + width + '" ' +
196
+ 'width="1.5em" height="1.5em"' +
197
+ '/>';
198
+ break;
199
+ case 'rectangle':
200
+ html = '<use xlink:href="#rectangle" class="legendIcon" ' +
201
+ 'x="' + x + '" ' +
202
+ 'y="' + y + '" ' +
203
+ 'fill="' + fill + '" ' +
204
+ 'stroke="' + stroke + '" ' +
205
+ 'stroke-width="' + width + '" ' +
206
+ 'width="1.5em" height="1.5em"' +
207
+ '/>';
208
+ break;
209
+ case 'plus':
210
+ html = '<use xlink:href="#plus" class="legendIcon" ' +
211
+ 'x="' + x + '" ' +
212
+ 'y="' + y + '" ' +
213
+ // 'fill="' + fill + '" ' +
214
+ 'stroke="' + stroke + '" ' +
215
+ 'stroke-width="' + width + '" ' +
216
+ 'width="1.5em" height="1.5em"' +
217
+ '/>';
218
+ break;
219
+ case 'bar':
220
+ html = '<use xlink:href="#bars" class="legendIcon" ' +
221
+ 'x="' + x + '" ' +
222
+ 'y="' + y + '" ' +
223
+ 'fill="' + fill + '" ' +
224
+ // 'stroke="' + stroke + '" ' +
225
+ // 'stroke-width="' + width + '" ' +
226
+ 'width="1.5em" height="1.5em"' +
227
+ '/>';
228
+ break;
229
+ case 'area':
230
+ html = '<use xlink:href="#area" class="legendIcon" ' +
231
+ 'x="' + x + '" ' +
232
+ 'y="' + y + '" ' +
233
+ 'fill="' + fill + '" ' +
234
+ // 'stroke="' + stroke + '" ' +
235
+ // 'stroke-width="' + width + '" ' +
236
+ 'width="1.5em" height="1.5em"' +
237
+ '/>';
238
+ break;
239
+ case 'line':
240
+ html = '<use xlink:href="#line" class="legendIcon" ' +
241
+ 'x="' + x + '" ' +
242
+ 'y="' + y + '" ' +
243
+ // 'fill="' + fill + '" ' +
244
+ 'stroke="' + stroke + '" ' +
245
+ 'stroke-width="' + width + '" ' +
246
+ 'width="1.5em" height="1.5em"' +
247
+ '/>';
248
+ break;
249
+ default:
250
+ // default is circle
251
+ html = '<use xlink:href="#circle" class="legendIcon" ' +
252
+ 'x="' + x + '" ' +
253
+ 'y="' + y + '" ' +
254
+ 'fill="' + fill + '" ' +
255
+ 'stroke="' + stroke + '" ' +
256
+ 'stroke-width="' + width + '" ' +
257
+ 'width="1.5em" height="1.5em"' +
258
+ '/>';
259
+ }
260
+
261
+ return html;
262
+ }
263
+
264
+ // Define svg symbols for shapes
265
+ var svgShapeDefs = '' +
266
+ '<defs>' +
267
+ '<symbol id="line" fill="none" viewBox="-5 -5 25 25">' +
268
+ '<polyline points="0,15 5,5 10,10 15,0"/>' +
269
+ '</symbol>' +
270
+
271
+ '<symbol id="area" stroke-width="1" viewBox="-5 -5 25 25">' +
272
+ '<polyline points="0,15 5,5 10,10 15,0, 15,15, 0,15"/>' +
273
+ '</symbol>' +
274
+
275
+ '<symbol id="bars" stroke-width="1" viewBox="-5 -5 25 25">' +
276
+ '<polyline points="1.5,15.5 1.5,12.5, 4.5,12.5 4.5,15.5 6.5,15.5 6.5,3.5, 9.5,3.5 9.5,15.5 11.5,15.5 11.5,7.5 14.5,7.5 14.5,15.5 1.5,15.5"/>' +
277
+ '</symbol>' +
278
+
279
+ '<symbol id="circle" viewBox="-5 -5 25 25">' +
280
+ '<circle cx="0" cy="15" r="2.5"/>' +
281
+ '<circle cx="5" cy="5" r="2.5"/>' +
282
+ '<circle cx="10" cy="10" r="2.5"/>' +
283
+ '<circle cx="15" cy="0" r="2.5"/>' +
284
+ '</symbol>' +
285
+
286
+ '<symbol id="rectangle" viewBox="-5 -5 25 25">' +
287
+ '<rect x="-2.1" y="12.9" width="4.2" height="4.2"/>' +
288
+ '<rect x="2.9" y="2.9" width="4.2" height="4.2"/>' +
289
+ '<rect x="7.9" y="7.9" width="4.2" height="4.2"/>' +
290
+ '<rect x="12.9" y="-2.1" width="4.2" height="4.2"/>' +
291
+ '</symbol>' +
292
+
293
+ '<symbol id="diamond" viewBox="-5 -5 25 25">' +
294
+ '<path d="M-3,15 L0,12 L3,15, L0,18 Z"/>' +
295
+ '<path d="M2,5 L5,2 L8,5, L5,8 Z"/>' +
296
+ '<path d="M7,10 L10,7 L13,10, L10,13 Z"/>' +
297
+ '<path d="M12,0 L15,-3 L18,0, L15,3 Z"/>' +
298
+ '</symbol>' +
299
+
300
+ '<symbol id="cross" fill="none" viewBox="-5 -5 25 25">' +
301
+ '<path d="M-2.1,12.9 L2.1,17.1, M2.1,12.9 L-2.1,17.1 Z"/>' +
302
+ '<path d="M2.9,2.9 L7.1,7.1 M7.1,2.9 L2.9,7.1 Z"/>' +
303
+ '<path d="M7.9,7.9 L12.1,12.1 M12.1,7.9 L7.9,12.1 Z"/>' +
304
+ '<path d="M12.9,-2.1 L17.1,2.1 M17.1,-2.1 L12.9,2.1 Z"/>' +
305
+ '</symbol>' +
306
+
307
+ '<symbol id="plus" fill="none" viewBox="-5 -5 25 25">' +
308
+ '<path d="M0,12 L0,18, M-3,15 L3,15 Z"/>' +
309
+ '<path d="M5,2 L5,8 M2,5 L8,5 Z"/>' +
310
+ '<path d="M10,7 L10,13 M7,10 L13,10 Z"/>' +
311
+ '<path d="M15,-3 L15,3 M12,0 L18,0 Z"/>' +
312
+ '</symbol>' +
313
+ '</defs>';
314
+
315
+ // Generate a list of legend entries in their final order
316
+ function getLegendEntries(series, labelFormatter, sorted) {
317
+ var lf = labelFormatter,
318
+ legendEntries = series.reduce(function(validEntries, s, i) {
319
+ var labelEval = (lf ? lf(s.label, s) : s.label)
320
+ if (s.hasOwnProperty("label") ? labelEval : true) {
321
+ var entry = {
322
+ label: labelEval || 'Plot ' + (i + 1),
323
+ color: s.color,
324
+ options: {
325
+ lines: s.lines,
326
+ points: s.points,
327
+ bars: s.bars
328
+ }
329
+ }
330
+ validEntries.push(entry)
331
+ }
332
+ return validEntries;
333
+ }, []);
334
+
335
+ // Sort the legend using either the default or a custom comparator
336
+ if (sorted) {
337
+ if ($.isFunction(sorted)) {
338
+ legendEntries.sort(sorted);
339
+ } else if (sorted === 'reverse') {
340
+ legendEntries.reverse();
341
+ } else {
342
+ var ascending = (sorted !== 'descending');
343
+ legendEntries.sort(function(a, b) {
344
+ return a.label === b.label
345
+ ? 0
346
+ : ((a.label < b.label) !== ascending ? 1 : -1 // Logical XOR
347
+ );
348
+ });
349
+ }
350
+ }
351
+
352
+ return legendEntries;
353
+ }
354
+
355
+ // return false if opts1 same as opts2
356
+ function checkOptions(opts1, opts2) {
357
+ for (var prop in opts1) {
358
+ if (opts1.hasOwnProperty(prop)) {
359
+ if (opts1[prop] !== opts2[prop]) {
360
+ return true;
361
+ }
362
+ }
363
+ }
364
+ return false;
365
+ }
366
+
367
+ // Compare two lists of legend entries
368
+ function shouldRedraw(oldEntries, newEntries) {
369
+ if (!oldEntries || !newEntries) {
370
+ return true;
371
+ }
372
+
373
+ if (oldEntries.length !== newEntries.length) {
374
+ return true;
375
+ }
376
+ var i, newEntry, oldEntry, newOpts, oldOpts;
377
+ for (i = 0; i < newEntries.length; i++) {
378
+ newEntry = newEntries[i];
379
+ oldEntry = oldEntries[i];
380
+
381
+ if (newEntry.label !== oldEntry.label) {
382
+ return true;
383
+ }
384
+
385
+ if (newEntry.color !== oldEntry.color) {
386
+ return true;
387
+ }
388
+
389
+ // check for changes in lines options
390
+ newOpts = newEntry.options.lines;
391
+ oldOpts = oldEntry.options.lines;
392
+ if (checkOptions(newOpts, oldOpts)) {
393
+ return true;
394
+ }
395
+
396
+ // check for changes in points options
397
+ newOpts = newEntry.options.points;
398
+ oldOpts = oldEntry.options.points;
399
+ if (checkOptions(newOpts, oldOpts)) {
400
+ return true;
401
+ }
402
+
403
+ // check for changes in bars options
404
+ newOpts = newEntry.options.bars;
405
+ oldOpts = oldEntry.options.bars;
406
+ if (checkOptions(newOpts, oldOpts)) {
407
+ return true;
408
+ }
409
+ }
410
+
411
+ return false;
412
+ }
413
+
414
+ function init(plot) {
415
+ plot.hooks.setupGrid.push(function (plot) {
416
+ var options = plot.getOptions();
417
+ var series = plot.getData(),
418
+ labelFormatter = options.legend.labelFormatter,
419
+ oldEntries = options.legend.legendEntries,
420
+ oldPlotOffset = options.legend.plotOffset,
421
+ newEntries = getLegendEntries(series, labelFormatter, options.legend.sorted),
422
+ newPlotOffset = plot.getPlotOffset();
423
+
424
+ if (shouldRedraw(oldEntries, newEntries) ||
425
+ checkOptions(oldPlotOffset, newPlotOffset)) {
426
+ insertLegend(plot, options, plot.getPlaceholder(), newEntries);
427
+ }
428
+ });
429
+ }
430
+
431
+ $.plot.plugins.push({
432
+ init: init,
433
+ options: defaultOptions,
434
+ name: 'legend',
435
+ version: '1.0'
436
+ });
437
+ })(jQuery);