rgraph-rails 1.0.7 → 1.0.8
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.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/lib/rgraph-rails/version.rb +1 -1
- data/license.txt +4 -16
- data/vendor/assets/javascripts/RGraph.bar.js +3734 -241
- data/vendor/assets/javascripts/RGraph.bipolar.js +2005 -115
- data/vendor/assets/javascripts/RGraph.common.annotate.js +395 -35
- data/vendor/assets/javascripts/RGraph.common.context.js +595 -30
- data/vendor/assets/javascripts/RGraph.common.core.js +5282 -405
- data/vendor/assets/javascripts/RGraph.common.csv.js +276 -19
- data/vendor/assets/javascripts/RGraph.common.deprecated.js +450 -35
- data/vendor/assets/javascripts/RGraph.common.dynamic.js +1395 -86
- data/vendor/assets/javascripts/RGraph.common.effects.js +1545 -90
- data/vendor/assets/javascripts/RGraph.common.key.js +753 -54
- data/vendor/assets/javascripts/RGraph.common.resizing.js +563 -37
- data/vendor/assets/javascripts/RGraph.common.sheets.js +352 -29
- data/vendor/assets/javascripts/RGraph.common.tooltips.js +450 -32
- data/vendor/assets/javascripts/RGraph.common.zoom.js +219 -14
- data/vendor/assets/javascripts/RGraph.drawing.background.js +570 -35
- data/vendor/assets/javascripts/RGraph.drawing.circle.js +544 -35
- data/vendor/assets/javascripts/RGraph.drawing.image.js +755 -52
- data/vendor/assets/javascripts/RGraph.drawing.marker1.js +645 -41
- data/vendor/assets/javascripts/RGraph.drawing.marker2.js +633 -37
- data/vendor/assets/javascripts/RGraph.drawing.marker3.js +514 -36
- data/vendor/assets/javascripts/RGraph.drawing.poly.js +559 -39
- data/vendor/assets/javascripts/RGraph.drawing.rect.js +548 -35
- data/vendor/assets/javascripts/RGraph.drawing.text.js +664 -36
- data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +812 -50
- data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +856 -51
- data/vendor/assets/javascripts/RGraph.fuel.js +964 -58
- data/vendor/assets/javascripts/RGraph.funnel.js +984 -55
- data/vendor/assets/javascripts/RGraph.gantt.js +1354 -77
- data/vendor/assets/javascripts/RGraph.gauge.js +1421 -87
- data/vendor/assets/javascripts/RGraph.hbar.js +2562 -146
- data/vendor/assets/javascripts/RGraph.hprogress.js +1401 -80
- data/vendor/assets/javascripts/RGraph.line.js +4226 -244
- data/vendor/assets/javascripts/RGraph.meter.js +1280 -74
- data/vendor/assets/javascripts/RGraph.modaldialog.js +301 -19
- data/vendor/assets/javascripts/RGraph.odo.js +1264 -71
- data/vendor/assets/javascripts/RGraph.pie.js +2288 -137
- data/vendor/assets/javascripts/RGraph.radar.js +1847 -110
- data/vendor/assets/javascripts/RGraph.rose.js +1977 -108
- data/vendor/assets/javascripts/RGraph.rscatter.js +1432 -80
- data/vendor/assets/javascripts/RGraph.scatter.js +3036 -168
- data/vendor/assets/javascripts/RGraph.semicircularprogress.js +1120 -60
- data/vendor/assets/javascripts/RGraph.svg.bar.js +1067 -0
- data/vendor/assets/javascripts/RGraph.svg.common.ajax.js +247 -0
- data/vendor/assets/javascripts/RGraph.svg.common.core.js +3363 -0
- data/vendor/assets/javascripts/RGraph.svg.common.csv.js +277 -0
- data/vendor/assets/javascripts/RGraph.svg.common.fx.js +1304 -0
- data/vendor/assets/javascripts/RGraph.svg.common.sheets.js +353 -0
- data/vendor/assets/javascripts/RGraph.svg.common.tooltips.js +233 -0
- data/vendor/assets/javascripts/RGraph.svg.hbar.js +1141 -0
- data/vendor/assets/javascripts/RGraph.svg.line.js +1486 -0
- data/vendor/assets/javascripts/RGraph.svg.pie.js +781 -0
- data/vendor/assets/javascripts/RGraph.svg.radar.js +1326 -0
- data/vendor/assets/javascripts/RGraph.svg.semicircularprogress.js +817 -0
- data/vendor/assets/javascripts/RGraph.thermometer.js +1135 -62
- data/vendor/assets/javascripts/RGraph.vprogress.js +1470 -83
- data/vendor/assets/javascripts/RGraph.waterfall.js +1347 -80
- metadata +15 -3
@@ -0,0 +1,1486 @@
|
|
1
|
+
// version: 2017-01-02
|
2
|
+
/**
|
3
|
+
* o--------------------------------------------------------------------------------o
|
4
|
+
* | This file is part of the RGraph package - you can learn more at: |
|
5
|
+
* | |
|
6
|
+
* | http://www.rgraph.net |
|
7
|
+
* | |
|
8
|
+
* | RGraph is licensed under the Open Source MIT license. That means that it's |
|
9
|
+
* | totally free to use! |
|
10
|
+
* o--------------------------------------------------------------------------------o
|
11
|
+
*/
|
12
|
+
|
13
|
+
RGraph = window.RGraph || {isRGraph: true};
|
14
|
+
RGraph.SVG = RGraph.SVG || {};
|
15
|
+
|
16
|
+
// Module pattern
|
17
|
+
(function (win, doc, undefined)
|
18
|
+
{
|
19
|
+
var RG = RGraph,
|
20
|
+
ua = navigator.userAgent,
|
21
|
+
ma = Math,
|
22
|
+
win = window,
|
23
|
+
doc = document;
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
RG.SVG.Line = function (conf)
|
28
|
+
{
|
29
|
+
this.id = conf.id;
|
30
|
+
this.uid = RG.SVG.createUID();
|
31
|
+
this.container = document.getElementById(this.id);
|
32
|
+
this.svg = RG.SVG.createSVG({container: this.container});
|
33
|
+
this.isRGraph = true;
|
34
|
+
this.width = Number(this.svg.getAttribute('width'));
|
35
|
+
this.height = Number(this.svg.getAttribute('height'));
|
36
|
+
|
37
|
+
// Convert single datasets to a multi-dimensional format
|
38
|
+
if (RG.SVG.isArray(conf.data) && RG.SVG.isArray(conf.data[0])) {
|
39
|
+
this.data = RG.SVG.arrayClone(conf.data);
|
40
|
+
} else if (RG.SVG.isArray(conf.data)) {
|
41
|
+
this.data = [RG.SVG.arrayClone(conf.data)];
|
42
|
+
} else {
|
43
|
+
this.data = [[]];
|
44
|
+
}
|
45
|
+
|
46
|
+
this.type = 'line';
|
47
|
+
this.coords = [];
|
48
|
+
this.coords2 = [];
|
49
|
+
this.coordsSpline = [];
|
50
|
+
this.hasMultipleDatasets = typeof this.data[0] === 'object' && typeof this.data[1] === 'object' ? true : false;
|
51
|
+
this.colorsParsed = false;
|
52
|
+
this.originalColors = {};
|
53
|
+
this.gradientCounter = 1;
|
54
|
+
this.originalData = RG.SVG.arrayClone(this.data);
|
55
|
+
|
56
|
+
// Add this object to the ObjectRegistry
|
57
|
+
RG.SVG.OR.add(this);
|
58
|
+
|
59
|
+
this.container.style.display = 'inline-block';
|
60
|
+
|
61
|
+
this.properties =
|
62
|
+
{
|
63
|
+
gutterLeft: 35,
|
64
|
+
gutterRight: 35,
|
65
|
+
gutterTop: 35,
|
66
|
+
gutterBottom: 35,
|
67
|
+
|
68
|
+
backgroundGrid: true,
|
69
|
+
backgroundGridColor: '#ddd',
|
70
|
+
backgroundGridLinewidth: 1,
|
71
|
+
backgroundGridHlines: true,
|
72
|
+
backgroundGridHlinesCount: null,
|
73
|
+
backgroundGridVlines: true,
|
74
|
+
backgroundGridVlinesCount: null,
|
75
|
+
backgroundGridBorder: true,
|
76
|
+
|
77
|
+
colors: ['red', '#0f0', 'blue', '#ff0', '#0ff', 'green'],
|
78
|
+
|
79
|
+
fill: false,
|
80
|
+
filledColors: [],
|
81
|
+
filledClick: null,
|
82
|
+
filledOpacity: 1,
|
83
|
+
filledAccumulative: false,
|
84
|
+
|
85
|
+
hmargin: 0,
|
86
|
+
|
87
|
+
yaxis: true,
|
88
|
+
yaxisTickmarks: true,
|
89
|
+
yaxisTickmarksLength: 3,
|
90
|
+
yaxisColor: 'black',
|
91
|
+
|
92
|
+
yaxisScale: true,
|
93
|
+
yaxisLabels: null,
|
94
|
+
yaxisLabelsOffsetx: 0,
|
95
|
+
yaxisLabelsOffsety: 0,
|
96
|
+
yaxisLabelsCount: 5,
|
97
|
+
|
98
|
+
yaxisUnitsPre: '',
|
99
|
+
yaxisUnitsPost: '',
|
100
|
+
yaxisStrict: false,
|
101
|
+
yaxisDecimals: 0,
|
102
|
+
yaxisPoint: '.',
|
103
|
+
yaxisThousand: ',',
|
104
|
+
yaxisRound: false,
|
105
|
+
yaxisMax: null,
|
106
|
+
yaxisMin: 0,
|
107
|
+
yaxisFormatter: null,
|
108
|
+
|
109
|
+
xaxis: true,
|
110
|
+
xaxisTickmarks: true,
|
111
|
+
xaxisTickmarksLength: 3,
|
112
|
+
xaxisLabels: null,
|
113
|
+
xaxisLabelsOffsetx: 0,
|
114
|
+
xaxisLabelsOffsety: 0,
|
115
|
+
xaxisLabelsPosition: 'edge',
|
116
|
+
xaxisLabelsPositionEdgeTickmarksCount: null,
|
117
|
+
xaxisColor: 'black',
|
118
|
+
|
119
|
+
textColor: 'black',
|
120
|
+
textFont: 'sans-serif',
|
121
|
+
textSize: 12,
|
122
|
+
textBold: false,
|
123
|
+
textItalic: false,
|
124
|
+
|
125
|
+
linewidth: 1,
|
126
|
+
|
127
|
+
tooltips: null,
|
128
|
+
tooltipsOverride: null,
|
129
|
+
tooltipsEffect: 'fade',
|
130
|
+
tooltipsCssClass: 'RGraph_tooltip',
|
131
|
+
tooltipsEvent: 'mousemove',
|
132
|
+
|
133
|
+
highlightStroke: 'rgba(0,0,0,0)',
|
134
|
+
highlightFill: 'rgba(255,255,255,0.7)',
|
135
|
+
highlightLinewidth: 1,
|
136
|
+
|
137
|
+
tickmarksStyle: 'none',
|
138
|
+
tickmarksSize: 5,
|
139
|
+
tickmarksFill: 'white',
|
140
|
+
tickmarksLinewidth: 1,
|
141
|
+
|
142
|
+
labelsAbove: false,
|
143
|
+
labelsAboveFont: null,
|
144
|
+
labelsAboveSize: null,
|
145
|
+
labelsAboveBold: null,
|
146
|
+
labelsAboveItalic: null,
|
147
|
+
labelsAboveColor: null,
|
148
|
+
labelsAboveBackground: 'rgba(255,255,255,0.7)',
|
149
|
+
labelsAboveBackgroundPadding: 2,
|
150
|
+
labelsAboveUnitsPre: null,
|
151
|
+
labelsAboveUnitsPost: null,
|
152
|
+
labelsAbovePoint: null,
|
153
|
+
labelsAboveThousand: null,
|
154
|
+
labelsAboveFormatter: null,
|
155
|
+
labelsAboveDecimals: null,
|
156
|
+
labelsAboveOffsetx: 0,
|
157
|
+
labelsAboveOffsety: -10,
|
158
|
+
labelsAboveHalign: 'center',
|
159
|
+
labelsAboveValign: 'bottom',
|
160
|
+
|
161
|
+
shadow: false,
|
162
|
+
shadowOffsetx: 2,
|
163
|
+
shadowOffsety: 2,
|
164
|
+
shadowBlur: 2,
|
165
|
+
shadowOpacity: 0.25,
|
166
|
+
|
167
|
+
spline: false,
|
168
|
+
|
169
|
+
title: '',
|
170
|
+
titleSize: null,
|
171
|
+
titleX: null,
|
172
|
+
titleY: null,
|
173
|
+
titleHalign: 'center',
|
174
|
+
titleValign: 'bottom',
|
175
|
+
titleColor: null,
|
176
|
+
titleFont: null,
|
177
|
+
titleBold: false,
|
178
|
+
titleItalic: false,
|
179
|
+
|
180
|
+
titleSubtitle: '',
|
181
|
+
titleSubtitleSize: 10,
|
182
|
+
titleSubtitleX: null,
|
183
|
+
titleSubtitleY: null,
|
184
|
+
titleSubtitleHalign: 'center',
|
185
|
+
titleSubtitleValign: 'top',
|
186
|
+
titleSubtitleColor: '#aaa',
|
187
|
+
titleSubtitleFont: null,
|
188
|
+
titleSubtitleBold: false,
|
189
|
+
titleSubtitleItalic: false,
|
190
|
+
|
191
|
+
attribution: true,
|
192
|
+
attributionX: null,
|
193
|
+
attributionY: null,
|
194
|
+
attributionHref: 'http://www.rgraph.net/svg/index.html',
|
195
|
+
attributionHalign: 'right',
|
196
|
+
attributionValign: 'bottom',
|
197
|
+
attributionSize: 8,
|
198
|
+
attributionColor: 'gray',
|
199
|
+
attributionFont: 'sans-serif',
|
200
|
+
attributionItalic: false,
|
201
|
+
attributionBold: false
|
202
|
+
};
|
203
|
+
|
204
|
+
|
205
|
+
|
206
|
+
|
207
|
+
|
208
|
+
/**
|
209
|
+
* "Decorate" the object with the generic effects if the effects library has been included
|
210
|
+
*/
|
211
|
+
if (RG.SVG.FX && typeof RG.SVG.FX.decorate === 'function') {
|
212
|
+
RG.SVG.FX.decorate(this);
|
213
|
+
}
|
214
|
+
|
215
|
+
|
216
|
+
|
217
|
+
|
218
|
+
var prop = this.properties;
|
219
|
+
|
220
|
+
|
221
|
+
|
222
|
+
|
223
|
+
//
|
224
|
+
// A setter that the constructor uses (at the end)
|
225
|
+
// to set all of the properties
|
226
|
+
//
|
227
|
+
// @param string name The name of the property to set
|
228
|
+
// @param string value The value to set the property to
|
229
|
+
//
|
230
|
+
this.set = function (name, value)
|
231
|
+
{
|
232
|
+
if (arguments.length === 1 && typeof name === 'object') {
|
233
|
+
for (i in arguments[0]) {
|
234
|
+
if (typeof i === 'string') {
|
235
|
+
this.set(i, arguments[0][i]);
|
236
|
+
}
|
237
|
+
}
|
238
|
+
} else {
|
239
|
+
this.properties[name] = value;
|
240
|
+
}
|
241
|
+
|
242
|
+
return this;
|
243
|
+
};
|
244
|
+
|
245
|
+
|
246
|
+
|
247
|
+
|
248
|
+
|
249
|
+
|
250
|
+
|
251
|
+
|
252
|
+
//
|
253
|
+
// The draw method draws the Bar chart
|
254
|
+
//
|
255
|
+
this.draw = function ()
|
256
|
+
{
|
257
|
+
// Fire the beforedraw event
|
258
|
+
RG.SVG.fireCustomEvent(this, 'onbeforedraw');
|
259
|
+
|
260
|
+
|
261
|
+
|
262
|
+
|
263
|
+
|
264
|
+
// Create the defs tag
|
265
|
+
RG.SVG.createDefs(this);
|
266
|
+
|
267
|
+
|
268
|
+
|
269
|
+
|
270
|
+
|
271
|
+
this.graphWidth = this.width - prop.gutterLeft - prop.gutterRight;
|
272
|
+
this.graphHeight = this.height - prop.gutterTop - prop.gutterBottom;
|
273
|
+
|
274
|
+
|
275
|
+
|
276
|
+
/**
|
277
|
+
* Parse the colors. This allows for simple gradient syntax
|
278
|
+
*/
|
279
|
+
if (!this.colorsParsed) {
|
280
|
+
|
281
|
+
this.parseColors();
|
282
|
+
|
283
|
+
// Don't want to do this again
|
284
|
+
this.colorsParsed = true;
|
285
|
+
}
|
286
|
+
|
287
|
+
// Clear the coords arrays
|
288
|
+
this.coords = [];
|
289
|
+
this.coords2 = [];
|
290
|
+
this.coordsSpline = [];
|
291
|
+
|
292
|
+
// Reset the data back to the original
|
293
|
+
this.data = RG.SVG.arrayClone(this.originalData);
|
294
|
+
|
295
|
+
|
296
|
+
// Set this to zero
|
297
|
+
this.tooltipsSequentialIndex = 0;
|
298
|
+
|
299
|
+
|
300
|
+
// Go through the data and work out the maximum value
|
301
|
+
var values = [];
|
302
|
+
|
303
|
+
for (var i=0,max=0; i<this.data.length; ++i) {
|
304
|
+
if (typeof this.data[i] === 'number') {
|
305
|
+
values.push(this.data[i]);
|
306
|
+
|
307
|
+
} else if (RG.SVG.isArray(this.data[i]) && (!prop.filled || !prop.filledAccumulative) ) {
|
308
|
+
values.push(RG.SVG.arrayMax(this.data[i]));
|
309
|
+
|
310
|
+
} else if (RG.SVG.isArray(this.data[i]) && prop.filled && prop.filledAccumulative) {
|
311
|
+
for (var j=0; j<this.data[i].length; ++j) {
|
312
|
+
values[j] = values[j] || 0;
|
313
|
+
values[j] = values[j] + this.data[i][j];
|
314
|
+
|
315
|
+
// This adds values to prior values in order
|
316
|
+
// to create the stacking effect.
|
317
|
+
this.data[i][j] = values[j];
|
318
|
+
}
|
319
|
+
}
|
320
|
+
}
|
321
|
+
|
322
|
+
var max = RG.SVG.arrayMax(values);
|
323
|
+
|
324
|
+
// A custom, user-specified maximum value
|
325
|
+
if (typeof prop.yaxisMax === 'number') {
|
326
|
+
max = prop.yaxisMax;
|
327
|
+
}
|
328
|
+
|
329
|
+
// Set the ymin to zero if it's set mirror
|
330
|
+
if (prop.yaxisMin === 'mirror') {
|
331
|
+
var mirrorScale = true;
|
332
|
+
prop.yaxisMin = 0;
|
333
|
+
}
|
334
|
+
|
335
|
+
|
336
|
+
//
|
337
|
+
// Generate an appropiate scale
|
338
|
+
//
|
339
|
+
this.scale = RG.SVG.getScale({
|
340
|
+
object: this,
|
341
|
+
numlabels: prop.yaxisLabelsCount,
|
342
|
+
unitsPre: prop.yaxisUnitsPre,
|
343
|
+
unitsPost: prop.yaxisUnitsPost,
|
344
|
+
max: max,
|
345
|
+
min: prop.yaxisMin,
|
346
|
+
point: prop.yaxisPoint,
|
347
|
+
round: prop.yaxisRound,
|
348
|
+
thousand: prop.yaxisThousand,
|
349
|
+
decimals: prop.yaxisDecimals,
|
350
|
+
strict: typeof prop.yaxisMax === 'number',
|
351
|
+
formatter: prop.yaxisFormatter
|
352
|
+
});
|
353
|
+
|
354
|
+
|
355
|
+
|
356
|
+
//
|
357
|
+
// Get the scale a second time if the ymin should be mirored
|
358
|
+
//
|
359
|
+
// Set the ymin to zero if it's szet mirror
|
360
|
+
if (mirrorScale) {
|
361
|
+
this.scale = RG.SVG.getScale({
|
362
|
+
object: this,
|
363
|
+
numlabels: prop.yaxisLabelsCount,
|
364
|
+
unitsPre: prop.yaxisUnitsPre,
|
365
|
+
unitsPost: prop.yaxisUnitsPost,
|
366
|
+
max: this.scale.max,
|
367
|
+
min: this.scale.max * -1,
|
368
|
+
point: prop.yaxisPoint,
|
369
|
+
round: false,
|
370
|
+
thousand: prop.yaxisThousand,
|
371
|
+
decimals: prop.yaxisDecimals,
|
372
|
+
strict: typeof prop.yaxisMax === 'number',
|
373
|
+
formatter: prop.yaxisFormatter
|
374
|
+
});
|
375
|
+
}
|
376
|
+
|
377
|
+
// Now the scale has been generated adopt its max value
|
378
|
+
this.max = this.scale.max;
|
379
|
+
this.min = this.scale.min;
|
380
|
+
prop.yaxisMax = this.scale.max;
|
381
|
+
prop.yaxisMin = this.scale.min;
|
382
|
+
|
383
|
+
|
384
|
+
|
385
|
+
|
386
|
+
// Draw the background first
|
387
|
+
RG.SVG.drawBackground(this);
|
388
|
+
|
389
|
+
|
390
|
+
// Draw the axes over the bars
|
391
|
+
RG.SVG.drawXAxis(this);
|
392
|
+
RG.SVG.drawYAxis(this);
|
393
|
+
|
394
|
+
|
395
|
+
for (var i=0; i<this.data.length; ++i) {
|
396
|
+
this.drawLine(this.data[i], i);
|
397
|
+
}
|
398
|
+
|
399
|
+
// Always redraw the liines now so that tickmarks are drawn
|
400
|
+
this.redrawLines();
|
401
|
+
|
402
|
+
|
403
|
+
// Draw the labelsAbove labels
|
404
|
+
this.drawLabelsAbove();
|
405
|
+
|
406
|
+
|
407
|
+
// Add the attribution link. If you're adding this elsewhere on your page/site
|
408
|
+
// and you don't want it displayed then there are options available to not
|
409
|
+
// show it.
|
410
|
+
RG.SVG.attribution(this);
|
411
|
+
|
412
|
+
|
413
|
+
|
414
|
+
// Add the event listener that clears the highlight if
|
415
|
+
// there is any. Must be MOUSEDOWN (ie before the click event)
|
416
|
+
var obj = this;
|
417
|
+
document.body.addEventListener('mousedown', function (e)
|
418
|
+
{
|
419
|
+
RG.SVG.removeHighlight(obj);
|
420
|
+
|
421
|
+
}, false);
|
422
|
+
|
423
|
+
|
424
|
+
|
425
|
+
// Fire the draw event
|
426
|
+
RG.SVG.fireCustomEvent(this, 'ondraw');
|
427
|
+
|
428
|
+
|
429
|
+
|
430
|
+
return this;
|
431
|
+
};
|
432
|
+
|
433
|
+
|
434
|
+
|
435
|
+
|
436
|
+
|
437
|
+
|
438
|
+
|
439
|
+
|
440
|
+
//
|
441
|
+
// Draws the bars
|
442
|
+
//
|
443
|
+
this.drawLine = function (data, index)
|
444
|
+
{
|
445
|
+
var coords = [],
|
446
|
+
path = [];
|
447
|
+
|
448
|
+
// Generate the coordinates
|
449
|
+
for (var i=0,len=data.length; i<len; ++i) {
|
450
|
+
|
451
|
+
var val = data[i],
|
452
|
+
x = (( (this.graphWidth - prop.hmargin - prop.hmargin) / (len - 1) ) * i) + prop.gutterLeft + prop.hmargin,
|
453
|
+
y = this.getYCoord(val);
|
454
|
+
|
455
|
+
coords.push([x, y]);
|
456
|
+
}
|
457
|
+
|
458
|
+
|
459
|
+
// Go through the coordinates and create the path that draws the line
|
460
|
+
for (var i=0; i<coords.length; ++i) {
|
461
|
+
|
462
|
+
if (i === 0 || RG.SVG.isNull(data[i]) || RG.SVG.isNull(data[i - 1])) {
|
463
|
+
var action = 'M';
|
464
|
+
} else {
|
465
|
+
var action = 'L';
|
466
|
+
}
|
467
|
+
|
468
|
+
path.push(action + '{1} {2}'.format(
|
469
|
+
coords[i][0],
|
470
|
+
coords[i][1]
|
471
|
+
));
|
472
|
+
}
|
473
|
+
|
474
|
+
|
475
|
+
|
476
|
+
|
477
|
+
|
478
|
+
|
479
|
+
//
|
480
|
+
// Add the coordinates to the coords arrays
|
481
|
+
//
|
482
|
+
this.coords[index] = RG.SVG.arrayClone(coords);
|
483
|
+
this.coords2[index] = RG.SVG.arrayClone(coords);
|
484
|
+
|
485
|
+
if (prop.spline) {
|
486
|
+
this.coordsSpline[index] = this.drawSpline(coords);
|
487
|
+
}
|
488
|
+
|
489
|
+
|
490
|
+
|
491
|
+
|
492
|
+
// If the line should be filled, draw the fill part
|
493
|
+
if (prop.filled === true || (typeof prop.filled === 'object' && prop.filled[index]) ) {
|
494
|
+
|
495
|
+
if (prop.spline) {
|
496
|
+
|
497
|
+
var fillPath = ['M{1} {2}'.format(
|
498
|
+
this.coordsSpline[index][0][0],
|
499
|
+
this.coordsSpline[index][0][1]
|
500
|
+
)];
|
501
|
+
|
502
|
+
for (var i=1; i<this.coordsSpline[index].length; ++i) {
|
503
|
+
fillPath.push('L{1} {2}'.format(
|
504
|
+
this.coordsSpline[index][i][0] + ((i === (this.coordsSpline[index].length) - 1) ? 1 : 0),
|
505
|
+
this.coordsSpline[index][i][1]
|
506
|
+
));
|
507
|
+
}
|
508
|
+
|
509
|
+
} else {
|
510
|
+
var fillPath = RG.SVG.arrayClone(path);
|
511
|
+
}
|
512
|
+
|
513
|
+
|
514
|
+
// Draw a line down to the X axis
|
515
|
+
fillPath.push('L{1} {2}'.format(
|
516
|
+
this.coords[index][this.coords[index].length - 1][0] + 1,
|
517
|
+
index > 0 && prop.filledAccumulative ? (prop.spline ? this.coordsSpline[index - 1][this.coordsSpline[index - 1].length - 1][1] : this.coords[index - 1][this.coords[index - 1].length - 1][1]) : this.getYCoord(prop.yaxisMin > 0 ? prop.yaxisMin : 0) + (prop.xaxis ? 0 : 1)
|
518
|
+
));
|
519
|
+
|
520
|
+
if (index > 0 && prop.filledAccumulative) {
|
521
|
+
|
522
|
+
var path2 = RG.SVG.arrayClone(path);
|
523
|
+
|
524
|
+
if (index > 0 && prop.filledAccumulative) {
|
525
|
+
if (prop.spline) {
|
526
|
+
for (var i=this.coordsSpline[index - 1].length-1; i>=0; --i) {
|
527
|
+
fillPath.push('L{1} {2}'.format(
|
528
|
+
this.coordsSpline[index - 1][i][0],
|
529
|
+
this.coordsSpline[index - 1][i][1]
|
530
|
+
));
|
531
|
+
}
|
532
|
+
} else {
|
533
|
+
for (var i=this.coords[index - 1].length-1; i>=0; --i) {
|
534
|
+
fillPath.push('L{1} {2}'.format(
|
535
|
+
this.coords[index - 1][i][0],
|
536
|
+
this.coords[index - 1][i][1]
|
537
|
+
));
|
538
|
+
}
|
539
|
+
}
|
540
|
+
}
|
541
|
+
} else {
|
542
|
+
|
543
|
+
// This is the bottom left corner. The +1 is so that
|
544
|
+
// the fill doesn't go over the axis
|
545
|
+
fillPath.push('L{1} {2}'.format(
|
546
|
+
this.coords[index][0][0] + (prop.yaxis ? 1 : 0),
|
547
|
+
this.getYCoord(prop.yaxisMin > 0 ? prop.yaxisMin : 0) + (prop.xaxis ? 0 : 1)
|
548
|
+
));
|
549
|
+
}
|
550
|
+
|
551
|
+
// Find the first none-null value and use that
|
552
|
+
// values X value
|
553
|
+
fillPath.push('L{1} {2}'.format(
|
554
|
+
this.coords[index][0][0] + (prop.yaxis ? 1 : 0),
|
555
|
+
this.coords[index][0][1]
|
556
|
+
));
|
557
|
+
|
558
|
+
for (var i=0; i<this.data[index].length; ++i) {
|
559
|
+
if (!RG.SVG.isNull(this.data[index][i])) {
|
560
|
+
fillPath.push('L{1} {2}'.format(
|
561
|
+
this.coords[index][i][0],
|
562
|
+
this.getYCoord(0)
|
563
|
+
));
|
564
|
+
break;
|
565
|
+
}
|
566
|
+
}
|
567
|
+
|
568
|
+
|
569
|
+
|
570
|
+
// Add the fill path to the scene
|
571
|
+
var fillPathObject = RG.SVG.create({
|
572
|
+
svg: this.svg,
|
573
|
+
type: 'path',
|
574
|
+
attr: {
|
575
|
+
d: fillPath.join(' '),
|
576
|
+
stroke: 'rgba(0,0,0,0)',
|
577
|
+
'fill': prop.filledColors && prop.filledColors[index] ? prop.filledColors[index] : prop.colors[index],
|
578
|
+
'fill-opacity': prop.filledOpacity,
|
579
|
+
'stroke-width': 1,
|
580
|
+
'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
|
581
|
+
}
|
582
|
+
});
|
583
|
+
|
584
|
+
|
585
|
+
if (prop.filledClick) {
|
586
|
+
|
587
|
+
var obj = this;
|
588
|
+
fillPathObject.onclick = function (e)
|
589
|
+
{
|
590
|
+
prop.filledClick(e, obj, index);
|
591
|
+
};
|
592
|
+
fillPathObject.onmousemove = function (e)
|
593
|
+
{
|
594
|
+
e.target.style.cursor = 'pointer';
|
595
|
+
}
|
596
|
+
}
|
597
|
+
}
|
598
|
+
|
599
|
+
|
600
|
+
|
601
|
+
|
602
|
+
|
603
|
+
|
604
|
+
|
605
|
+
|
606
|
+
|
607
|
+
//
|
608
|
+
// Create the drop shadow effect if its required
|
609
|
+
//
|
610
|
+
if (prop.shadow) {
|
611
|
+
RG.SVG.setShadow({
|
612
|
+
object: this,
|
613
|
+
offsetx: prop.shadowOffsetx,
|
614
|
+
offsety: prop.shadowOffsety,
|
615
|
+
blur: prop.shadowBlur,
|
616
|
+
opacity: prop.shadowOpacity,
|
617
|
+
id: 'dropShadow'
|
618
|
+
});
|
619
|
+
}
|
620
|
+
|
621
|
+
|
622
|
+
|
623
|
+
|
624
|
+
|
625
|
+
|
626
|
+
// Add the path to the scene
|
627
|
+
if (prop.spline) {
|
628
|
+
|
629
|
+
// Make the raw coords into a path
|
630
|
+
var str = ['M{1} {2}'.format(
|
631
|
+
this.coordsSpline[index][0][0],
|
632
|
+
this.coordsSpline[index][0][1]
|
633
|
+
)];
|
634
|
+
|
635
|
+
for (var i=1; i<this.coordsSpline[index].length; ++i) {
|
636
|
+
str.push('L{1} {2}'.format(
|
637
|
+
this.coordsSpline[index][i][0],
|
638
|
+
this.coordsSpline[index][i][1]
|
639
|
+
));
|
640
|
+
}
|
641
|
+
|
642
|
+
str = str.join(' ');
|
643
|
+
|
644
|
+
var line = RG.SVG.create({
|
645
|
+
svg: this.svg,
|
646
|
+
type: 'path',
|
647
|
+
attr: {
|
648
|
+
d: str,
|
649
|
+
stroke: prop['colors'][index],
|
650
|
+
'fill':'none',
|
651
|
+
'stroke-width': this.hasMultipleDatasets && prop.filled && prop.filledAccumulative ? 0.1 : (RG.SVG.isArray(prop.linewidth) ? prop.linewidth[index] : prop.linewidth + 0.01),
|
652
|
+
'stroke-linecap': 'round',
|
653
|
+
'stroke-linejoin': 'round',
|
654
|
+
filter: prop.shadow ? 'url(#dropShadow)' : '',
|
655
|
+
'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
|
656
|
+
}
|
657
|
+
});
|
658
|
+
|
659
|
+
} else {
|
660
|
+
|
661
|
+
var path2 = RG.SVG.arrayClone(path);
|
662
|
+
|
663
|
+
if (prop.filled && prop.filledAccumulative && index > 0) {
|
664
|
+
for (var i=this.coords[index - 1].length-1; i>=0; --i) {
|
665
|
+
path2.push('L{1} {2}'.format(
|
666
|
+
this.coords[index - 1][i][0],
|
667
|
+
this.coords[index - 1][i][1]
|
668
|
+
));
|
669
|
+
}
|
670
|
+
}
|
671
|
+
|
672
|
+
path2 = path2.join(' ');
|
673
|
+
|
674
|
+
var line = RG.SVG.create({
|
675
|
+
svg: this.svg,
|
676
|
+
type: 'path',
|
677
|
+
attr: {
|
678
|
+
d: path2,
|
679
|
+
stroke: prop.colors[index],
|
680
|
+
'fill':'none',
|
681
|
+
'stroke-width': this.hasMultipleDatasets && prop.filled && prop.filledAccumulative ? 0.1 : (RG.SVG.isArray(prop.linewidth) ? prop.linewidth[index]: prop.linewidth + 0.01),
|
682
|
+
'stroke-linecap': 'round',
|
683
|
+
'stroke-linejoin': 'round',
|
684
|
+
filter: prop.shadow ? 'url(#dropShadow)' : '',
|
685
|
+
'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
|
686
|
+
}
|
687
|
+
});
|
688
|
+
}
|
689
|
+
|
690
|
+
|
691
|
+
|
692
|
+
|
693
|
+
|
694
|
+
|
695
|
+
if (prop.tooltips && prop.tooltips.length) {
|
696
|
+
|
697
|
+
var group = RG.SVG.create({
|
698
|
+
svg: this.svg,
|
699
|
+
type: 'g',
|
700
|
+
attr: {
|
701
|
+
'fill': 'transparent',
|
702
|
+
className: "rgraph_hotspots"
|
703
|
+
},
|
704
|
+
style: {
|
705
|
+
cursor: 'pointer'
|
706
|
+
}
|
707
|
+
});
|
708
|
+
|
709
|
+
|
710
|
+
for (var i=0; i<this.coords[index].length; ++i,++this.tooltipsSequentialIndex) {
|
711
|
+
|
712
|
+
if (this.coords[index][i][0] && this.coords[index][i][1]) {
|
713
|
+
|
714
|
+
var hotspot = RG.SVG.create({
|
715
|
+
svg: this.svg,
|
716
|
+
parent: group,
|
717
|
+
type: 'circle',
|
718
|
+
attr: {
|
719
|
+
cx: this.coords[index][i][0],
|
720
|
+
cy: this.coords[index][i][1],
|
721
|
+
r: 5,
|
722
|
+
'data-dataset': index,
|
723
|
+
'data-index': i
|
724
|
+
}
|
725
|
+
});
|
726
|
+
|
727
|
+
var obj = this;
|
728
|
+
(function (sequentialIndex)
|
729
|
+
{
|
730
|
+
hotspot.addEventListener(prop.tooltipsEvent, function (e)
|
731
|
+
{
|
732
|
+
var indexes = RG.SVG.sequentialIndexToGrouped(sequentialIndex, obj.data),
|
733
|
+
index = indexes[1],
|
734
|
+
dataset = indexes[0];
|
735
|
+
|
736
|
+
|
737
|
+
if (RG.SVG.REG.get('tooltip') && RG.SVG.REG.get('tooltip').__index__ === index && RG.SVG.REG.get('tooltip').__dataset__ === dataset) {
|
738
|
+
return;
|
739
|
+
}
|
740
|
+
|
741
|
+
RG.SVG.hideTooltip();
|
742
|
+
|
743
|
+
// Show the tooltip
|
744
|
+
if (prop.tooltips[sequentialIndex]) {
|
745
|
+
var text = prop.tooltips[sequentialIndex];
|
746
|
+
}
|
747
|
+
|
748
|
+
RG.SVG.tooltip({
|
749
|
+
object: obj,
|
750
|
+
index: index,
|
751
|
+
dataset: dataset,
|
752
|
+
sequentialIndex: sequentialIndex,
|
753
|
+
text: text,
|
754
|
+
event: e
|
755
|
+
});
|
756
|
+
|
757
|
+
|
758
|
+
// Highlight the chart here
|
759
|
+
var outer_highlight1 = RG.SVG.create({
|
760
|
+
svg: obj.svg,
|
761
|
+
type: 'circle',
|
762
|
+
attr: {
|
763
|
+
cx: obj.coords[dataset][index][0],
|
764
|
+
cy: obj.coords[dataset][index][1],
|
765
|
+
r: 13,
|
766
|
+
fill: obj.properties.colors[dataset],
|
767
|
+
'fill-opacity': 0.5
|
768
|
+
},
|
769
|
+
style: {
|
770
|
+
cursor: 'pointer'
|
771
|
+
}
|
772
|
+
});
|
773
|
+
|
774
|
+
|
775
|
+
var outer_highlight2 = RG.SVG.create({
|
776
|
+
svg: obj.svg,
|
777
|
+
type: 'circle',
|
778
|
+
attr: {
|
779
|
+
cx: obj.coords[dataset][index][0],
|
780
|
+
cy: obj.coords[dataset][index][1],
|
781
|
+
r: 14,
|
782
|
+
fill: 'white',
|
783
|
+
'fill-opacity': 0.75
|
784
|
+
},
|
785
|
+
style: {
|
786
|
+
cursor: 'pointer'
|
787
|
+
}
|
788
|
+
});
|
789
|
+
|
790
|
+
|
791
|
+
var inner_highlight1 = RG.SVG.create({
|
792
|
+
svg: obj.svg,
|
793
|
+
type: 'circle',
|
794
|
+
attr: {
|
795
|
+
cx: obj.coords[dataset][index][0],
|
796
|
+
cy: obj.coords[dataset][index][1],
|
797
|
+
r: 6,
|
798
|
+
fill: 'white'
|
799
|
+
},
|
800
|
+
style: {
|
801
|
+
cursor: 'pointer'
|
802
|
+
}
|
803
|
+
});
|
804
|
+
|
805
|
+
|
806
|
+
var inner_highlight2 = RG.SVG.create({
|
807
|
+
svg: obj.svg,
|
808
|
+
type: 'circle',
|
809
|
+
attr: {
|
810
|
+
cx: obj.coords[dataset][index][0],
|
811
|
+
cy: obj.coords[dataset][index][1],
|
812
|
+
r: 5,
|
813
|
+
fill: obj.properties.colors[dataset]
|
814
|
+
},
|
815
|
+
style: {
|
816
|
+
cursor: 'pointer'
|
817
|
+
}
|
818
|
+
});
|
819
|
+
|
820
|
+
// Set the highlight in the registry
|
821
|
+
RG.SVG.REG.set('highlight', [
|
822
|
+
outer_highlight1,
|
823
|
+
outer_highlight2,
|
824
|
+
inner_highlight1,
|
825
|
+
inner_highlight2
|
826
|
+
]);
|
827
|
+
|
828
|
+
}, false);
|
829
|
+
})(this.tooltipsSequentialIndex);
|
830
|
+
|
831
|
+
}
|
832
|
+
}
|
833
|
+
}
|
834
|
+
};
|
835
|
+
|
836
|
+
|
837
|
+
|
838
|
+
|
839
|
+
|
840
|
+
|
841
|
+
|
842
|
+
|
843
|
+
//
|
844
|
+
// Draws tickmarks
|
845
|
+
//
|
846
|
+
// @param number index The index of the line/dataset of coordinates
|
847
|
+
// @param object data The origvinal line data points
|
848
|
+
// @param object coords The coordinates of the points
|
849
|
+
//
|
850
|
+
this.drawTickmarks = function (index, data, coords)
|
851
|
+
{
|
852
|
+
for (var i=0; i<data.length; ++i) {
|
853
|
+
|
854
|
+
if (typeof data[i] === 'number') {
|
855
|
+
switch (prop.tickmarksStyle) {
|
856
|
+
case 'filledcircle':
|
857
|
+
case 'filledendcircle':
|
858
|
+
if (prop.tickmarksStyle === 'filledcircle' || (i === 0 || i === data.length - 1) ) {
|
859
|
+
var circle = RG.SVG.create({
|
860
|
+
svg: this.svg,
|
861
|
+
type: 'circle',
|
862
|
+
attr: {
|
863
|
+
cx: coords[index][i][0],
|
864
|
+
cy: coords[index][i][1],
|
865
|
+
r: prop.tickmarksSize,
|
866
|
+
'fill': prop.colors[index],
|
867
|
+
filter: prop.shadow? 'url(#dropShadow)' : '',
|
868
|
+
'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
|
869
|
+
}
|
870
|
+
});
|
871
|
+
}
|
872
|
+
|
873
|
+
|
874
|
+
break;
|
875
|
+
|
876
|
+
case 'circle':
|
877
|
+
case 'endcircle':
|
878
|
+
|
879
|
+
if (prop.tickmarksStyle === 'circle' || (prop.tickmarksStyle === 'endcircle' && (i === 0 || i === data.length - 1)) ) {
|
880
|
+
|
881
|
+
var outerCircle = RG.SVG.create({
|
882
|
+
svg: this.svg,
|
883
|
+
type: 'circle',
|
884
|
+
attr: {
|
885
|
+
cx: coords[index][i][0],
|
886
|
+
cy: coords[index][i][1],
|
887
|
+
r: prop.tickmarksSize + prop.tickmarksLinewidth,
|
888
|
+
'fill': prop.colors[index],
|
889
|
+
filter: prop.shadow? 'url(#dropShadow)' : '',
|
890
|
+
'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
|
891
|
+
}
|
892
|
+
});
|
893
|
+
|
894
|
+
var innerCircle = RG.SVG.create({
|
895
|
+
svg: this.svg,
|
896
|
+
type: 'circle',
|
897
|
+
attr: {
|
898
|
+
cx: coords[index][i][0],
|
899
|
+
cy: coords[index][i][1],
|
900
|
+
r: prop.tickmarksSize,
|
901
|
+
'fill': prop.tickmarksFill,
|
902
|
+
'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
|
903
|
+
}
|
904
|
+
});
|
905
|
+
|
906
|
+
break;
|
907
|
+
}
|
908
|
+
break;
|
909
|
+
|
910
|
+
case 'endrect':
|
911
|
+
case 'rect':
|
912
|
+
if (prop.tickmarksStyle === 'rect' || (prop.tickmarksStyle === 'endrect' && (i === 0 || i === data.length - 1)) ) {
|
913
|
+
|
914
|
+
var half = (prop.tickmarksSize + prop.tickmarksLinewidth) / 2;
|
915
|
+
var fill = typeof prop.tickmarksFill === 'object'&& typeof prop.tickmarksFill[index] === 'string' ? prop.tickmarksFill[index] : prop.tickmarksFill;
|
916
|
+
|
917
|
+
var rect = RG.SVG.create({
|
918
|
+
svg: this.svg,
|
919
|
+
type: 'rect',
|
920
|
+
attr: {
|
921
|
+
x: coords[index][i][0] - half,
|
922
|
+
y: coords[index][i][1] - half,
|
923
|
+
width: prop.tickmarksSize+ prop.tickmarksLinewidth,
|
924
|
+
height: prop.tickmarksSize+ prop.tickmarksLinewidth,
|
925
|
+
|
926
|
+
'stroke-width': prop.tickmarksLinewidth,
|
927
|
+
'stroke': prop.colors[index],
|
928
|
+
'fill': fill,
|
929
|
+
'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
|
930
|
+
}
|
931
|
+
});
|
932
|
+
}
|
933
|
+
|
934
|
+
break;
|
935
|
+
|
936
|
+
case 'filledendrect':
|
937
|
+
case 'filledrect':
|
938
|
+
if (prop.tickmarksStyle === 'filledrect' || (prop.tickmarksStyle === 'filledendrect' && (i === 0 || i === data.length - 1)) ) {
|
939
|
+
|
940
|
+
var half = (prop.tickmarksSize + prop.tickmarksLinewidth) / 2;
|
941
|
+
var fill = prop.colors[index];
|
942
|
+
|
943
|
+
var rect = RG.SVG.create({
|
944
|
+
svg: this.svg,
|
945
|
+
type: 'rect',
|
946
|
+
attr: {
|
947
|
+
x: coords[index][i][0] - half,
|
948
|
+
y: coords[index][i][1] - half,
|
949
|
+
width: prop.tickmarksSize+ prop.tickmarksLinewidth,
|
950
|
+
height: prop.tickmarksSize+ prop.tickmarksLinewidth,
|
951
|
+
'fill': fill,
|
952
|
+
'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
|
953
|
+
}
|
954
|
+
});
|
955
|
+
}
|
956
|
+
}
|
957
|
+
}
|
958
|
+
}
|
959
|
+
};
|
960
|
+
|
961
|
+
|
962
|
+
|
963
|
+
|
964
|
+
|
965
|
+
|
966
|
+
|
967
|
+
|
968
|
+
//
|
969
|
+
// Redraws the line in certain circumstances:
|
970
|
+
// o filled
|
971
|
+
// o filledAccumulative
|
972
|
+
// o Multiple lines
|
973
|
+
//
|
974
|
+
this.redrawLines = function ()
|
975
|
+
{
|
976
|
+
if (prop.spline) {
|
977
|
+
for (var i=0; i<this.coordsSpline.length; ++i) {
|
978
|
+
|
979
|
+
var linewidth = RG.SVG.isArray(prop.linewidth) ? prop.linewidth[i] : prop.linewidth,
|
980
|
+
color = prop['colors'][i],
|
981
|
+
path = '';
|
982
|
+
|
983
|
+
// Create the path from the spline coordinates
|
984
|
+
for (var j=0; j<this.coordsSpline[i].length; ++j) {
|
985
|
+
if (j === 0) {
|
986
|
+
path += 'M{1} {2} '.format(
|
987
|
+
this.coordsSpline[i][j][0],
|
988
|
+
this.coordsSpline[i][j][1]
|
989
|
+
);
|
990
|
+
} else {
|
991
|
+
path += 'L{1} {2} '.format(
|
992
|
+
this.coordsSpline[i][j][0],
|
993
|
+
this.coordsSpline[i][j][1]
|
994
|
+
);
|
995
|
+
}
|
996
|
+
}
|
997
|
+
|
998
|
+
|
999
|
+
|
1000
|
+
RG.SVG.create({
|
1001
|
+
svg: this.svg,
|
1002
|
+
type: 'path',
|
1003
|
+
attr: {
|
1004
|
+
d: path,
|
1005
|
+
stroke: color,
|
1006
|
+
'fill':'none',
|
1007
|
+
'stroke-width': linewidth + 0.01,
|
1008
|
+
'stroke-linecap': 'round',
|
1009
|
+
'stroke-linejoin': 'round',
|
1010
|
+
filter: prop.shadow ? 'url(#dropShadow)' : '',
|
1011
|
+
'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
|
1012
|
+
}
|
1013
|
+
});
|
1014
|
+
}
|
1015
|
+
|
1016
|
+
|
1017
|
+
// Now draw the tickmarks
|
1018
|
+
for (var dataset=0; dataset<this.coords.length; ++dataset) {
|
1019
|
+
this.drawTickmarks(
|
1020
|
+
dataset,
|
1021
|
+
this.data[dataset],
|
1022
|
+
this.coords
|
1023
|
+
);
|
1024
|
+
}
|
1025
|
+
|
1026
|
+
} else {
|
1027
|
+
|
1028
|
+
|
1029
|
+
for (var i=0; i<this.coords.length; ++i) {
|
1030
|
+
|
1031
|
+
var linewidth = RG.SVG.isArray(prop.linewidth) ? prop.linewidth[i] : prop.linewidth,
|
1032
|
+
color = prop['colors'][i],
|
1033
|
+
path = '';
|
1034
|
+
|
1035
|
+
// Create the path from the coordinates
|
1036
|
+
for (var j=0; j<this.coords[i].length; ++j) {
|
1037
|
+
if (j === 0 || RG.SVG.isNull(this.data[i][j]) || RG.SVG.isNull(this.data[i][j - 1])) {
|
1038
|
+
path += 'M{1} {2} '.format(
|
1039
|
+
this.coords[i][j][0],
|
1040
|
+
this.coords[i][j][1]
|
1041
|
+
);
|
1042
|
+
} else {
|
1043
|
+
path += 'L{1} {2} '.format(
|
1044
|
+
this.coords[i][j][0],
|
1045
|
+
this.coords[i][j][1]
|
1046
|
+
);
|
1047
|
+
}
|
1048
|
+
}
|
1049
|
+
|
1050
|
+
|
1051
|
+
|
1052
|
+
RG.SVG.create({
|
1053
|
+
svg: this.svg,
|
1054
|
+
type: 'path',
|
1055
|
+
attr: {
|
1056
|
+
d: path,
|
1057
|
+
stroke: color,
|
1058
|
+
'fill':'none',
|
1059
|
+
'stroke-width': linewidth + 0.01,
|
1060
|
+
'stroke-linecap': 'round',
|
1061
|
+
'stroke-linejoin': 'round',
|
1062
|
+
filter: prop.shadow ? 'url(#dropshadow)' : '',
|
1063
|
+
'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : ''
|
1064
|
+
}
|
1065
|
+
});
|
1066
|
+
|
1067
|
+
}
|
1068
|
+
|
1069
|
+
// Now draw the tickmarks
|
1070
|
+
for (var dataset=0; dataset<this.coords.length; ++dataset) {
|
1071
|
+
this.drawTickmarks(
|
1072
|
+
dataset,
|
1073
|
+
this.data[dataset],
|
1074
|
+
this.coords
|
1075
|
+
);
|
1076
|
+
}
|
1077
|
+
}
|
1078
|
+
};
|
1079
|
+
|
1080
|
+
|
1081
|
+
|
1082
|
+
|
1083
|
+
|
1084
|
+
|
1085
|
+
|
1086
|
+
|
1087
|
+
/**
|
1088
|
+
* This function can be used to retrieve the relevant Y coordinate for a
|
1089
|
+
* particular value.
|
1090
|
+
*
|
1091
|
+
* @param int value The value to get the Y coordinate for
|
1092
|
+
*/
|
1093
|
+
this.getYCoord = function (value)
|
1094
|
+
{
|
1095
|
+
var prop = this.properties, y;
|
1096
|
+
|
1097
|
+
if (value > this.scale.max) {
|
1098
|
+
return null;
|
1099
|
+
}
|
1100
|
+
|
1101
|
+
if (value < this.scale.min) {
|
1102
|
+
return null;
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
y = ((value - this.scale.min) / (this.scale.max - this.scale.min));
|
1106
|
+
y *= (this.height - prop.gutterTop - prop.gutterBottom);
|
1107
|
+
|
1108
|
+
y = this.height - prop.gutterBottom - y;
|
1109
|
+
|
1110
|
+
return y;
|
1111
|
+
};
|
1112
|
+
|
1113
|
+
|
1114
|
+
|
1115
|
+
|
1116
|
+
|
1117
|
+
|
1118
|
+
|
1119
|
+
|
1120
|
+
/**
|
1121
|
+
* This function can be used to highlight a bar on the chart
|
1122
|
+
*
|
1123
|
+
* TODO This function looks like its needs updating
|
1124
|
+
*
|
1125
|
+
* @param object rect The rectangle to highlight
|
1126
|
+
*/
|
1127
|
+
this.highlight = function (rect)
|
1128
|
+
{
|
1129
|
+
var x = rect.getAttribute('x'),
|
1130
|
+
y = rect.getAttribute('y');
|
1131
|
+
|
1132
|
+
/*
|
1133
|
+
var highlight = RG.SVG.create({
|
1134
|
+
svg: this.svg,
|
1135
|
+
type: 'rect',
|
1136
|
+
attr: {
|
1137
|
+
stroke: prop.highlightStroke,
|
1138
|
+
fill: prop.highlightFill,
|
1139
|
+
x: x,
|
1140
|
+
y: y,
|
1141
|
+
width: width,
|
1142
|
+
height: height,
|
1143
|
+
'stroke-width': prop.highlightLinewidth
|
1144
|
+
}
|
1145
|
+
});
|
1146
|
+
|
1147
|
+
|
1148
|
+
if (prop.tooltipsEvent === 'mousemove') {
|
1149
|
+
highlight.addEventListener('mouseout', function (e)
|
1150
|
+
{
|
1151
|
+
highlight.parentNode.removeChild(highlight);
|
1152
|
+
RG.SVG.hideTooltip();
|
1153
|
+
|
1154
|
+
RG.SVG.REG.set('highlight', null);
|
1155
|
+
}, false);
|
1156
|
+
}
|
1157
|
+
|
1158
|
+
|
1159
|
+
// Store the highlight rect in the rebistry so
|
1160
|
+
// it can be cleared later
|
1161
|
+
RG.SVG.REG.set('highlight', highlight);
|
1162
|
+
*/
|
1163
|
+
};
|
1164
|
+
|
1165
|
+
|
1166
|
+
|
1167
|
+
|
1168
|
+
|
1169
|
+
|
1170
|
+
|
1171
|
+
|
1172
|
+
//
|
1173
|
+
// Draw a spline Line chart
|
1174
|
+
//
|
1175
|
+
// @param array coords The coords for the line
|
1176
|
+
//
|
1177
|
+
this.drawSpline = function (coords)
|
1178
|
+
{
|
1179
|
+
var xCoords = [];
|
1180
|
+
gutterLeft = prop.gutterLeft,
|
1181
|
+
gutterRight = prop.gutterRight,
|
1182
|
+
hmargin = prop.hmargin,
|
1183
|
+
interval = (this.graphWidth - (2 * hmargin)) / (coords.length - 1),
|
1184
|
+
coordsSpline = [];
|
1185
|
+
|
1186
|
+
/**
|
1187
|
+
* The drawSpline function takes an array of JUST Y coords - not X/Y coords. So the line coords need converting
|
1188
|
+
* if we've been given X/Y pairs
|
1189
|
+
*/
|
1190
|
+
for (var i=0,len=coords.length; i<len;i+=1) {
|
1191
|
+
if (typeof coords[i] == 'object' && coords[i] && coords[i].length == 2) {
|
1192
|
+
coords[i] = Number(coords[i][1]);
|
1193
|
+
}
|
1194
|
+
}
|
1195
|
+
|
1196
|
+
/**
|
1197
|
+
* Get the Points array in the format we want - the first value should
|
1198
|
+
* be null along with the lst value
|
1199
|
+
*/
|
1200
|
+
var P = [coords[0]];
|
1201
|
+
for (var i=0; i<coords.length; ++i) {
|
1202
|
+
P.push(coords[i]);
|
1203
|
+
}
|
1204
|
+
P.push(coords[coords.length - 1] + (coords[coords.length - 1] - coords[coords.length - 2]));
|
1205
|
+
|
1206
|
+
for (var j=1; j<P.length-2; ++j) {
|
1207
|
+
for (var t=0; t<10; ++t) {
|
1208
|
+
|
1209
|
+
var yCoord = spline( t/10, P[j-1], P[j], P[j+1], P[j+2] );
|
1210
|
+
|
1211
|
+
xCoords.push(((j-1) * interval) + (t * (interval / 10)) + gutterLeft + hmargin);
|
1212
|
+
|
1213
|
+
coordsSpline.push([
|
1214
|
+
xCoords[xCoords.length - 1],
|
1215
|
+
yCoord
|
1216
|
+
]);
|
1217
|
+
|
1218
|
+
if (typeof index === 'number') {
|
1219
|
+
coordsSpline[index].push([
|
1220
|
+
xCoords[xCoords.length - 1],
|
1221
|
+
yCoord
|
1222
|
+
]);
|
1223
|
+
}
|
1224
|
+
}
|
1225
|
+
}
|
1226
|
+
|
1227
|
+
|
1228
|
+
// Draw the last section
|
1229
|
+
coordsSpline.push([
|
1230
|
+
((j-1) * interval) + gutterLeft + hmargin,
|
1231
|
+
P[j]
|
1232
|
+
]);
|
1233
|
+
|
1234
|
+
if (typeof index === 'number') {
|
1235
|
+
coordsSpline.push([
|
1236
|
+
((j-1) * interval) + gutterLeft + hmargin,
|
1237
|
+
P[j]
|
1238
|
+
]);
|
1239
|
+
}
|
1240
|
+
|
1241
|
+
function spline (t, P0, P1, P2, P3)
|
1242
|
+
{
|
1243
|
+
return 0.5 * ((2 * P1) +
|
1244
|
+
((0-P0) + P2) * t +
|
1245
|
+
((2*P0 - (5*P1) + (4*P2) - P3) * (t*t) +
|
1246
|
+
((0-P0) + (3*P1)- (3*P2) + P3) * (t*t*t)));
|
1247
|
+
}
|
1248
|
+
|
1249
|
+
|
1250
|
+
return coordsSpline;
|
1251
|
+
};
|
1252
|
+
|
1253
|
+
|
1254
|
+
|
1255
|
+
|
1256
|
+
|
1257
|
+
|
1258
|
+
|
1259
|
+
|
1260
|
+
/**
|
1261
|
+
* This allows for easy specification of gradients
|
1262
|
+
*/
|
1263
|
+
this.parseColors = function ()
|
1264
|
+
{
|
1265
|
+
if (!Object.keys(this.originalColors).length) {
|
1266
|
+
this.originalColors = {
|
1267
|
+
colors: RG.SVG.arrayClone(prop.colors),
|
1268
|
+
filledColors: RG.SVG.arrayClone(prop.filledColors),
|
1269
|
+
backgroundGridColor: RG.SVG.arrayClone(prop.backgroundGridColor),
|
1270
|
+
highlightFill: RG.SVG.arrayClone(prop.highlightFill)
|
1271
|
+
}
|
1272
|
+
}
|
1273
|
+
|
1274
|
+
// colors
|
1275
|
+
var colors = prop.colors;
|
1276
|
+
|
1277
|
+
if (colors) {
|
1278
|
+
for (var i=0; i<colors.length; ++i) {
|
1279
|
+
colors[i] = RG.SVG.parseColorLinear({
|
1280
|
+
object: this,
|
1281
|
+
color: colors[i]
|
1282
|
+
});
|
1283
|
+
}
|
1284
|
+
}
|
1285
|
+
|
1286
|
+
|
1287
|
+
// Fill colors
|
1288
|
+
var filledColors = prop.filledColors;
|
1289
|
+
|
1290
|
+
if (filledColors) {
|
1291
|
+
for (var i=0; i<filledColors.length; ++i) {
|
1292
|
+
filledColors[i] = RG.SVG.parseColorLinear({
|
1293
|
+
object: this,
|
1294
|
+
color: filledColors[i]
|
1295
|
+
});
|
1296
|
+
}
|
1297
|
+
}
|
1298
|
+
|
1299
|
+
prop.backgroundGridColor = RG.SVG.parseColorLinear({object: this, color: prop.backgroundGridColor});
|
1300
|
+
prop.highlightFill = RG.SVG.parseColorLinear({object: this, color: prop.highlightFill});
|
1301
|
+
};
|
1302
|
+
|
1303
|
+
|
1304
|
+
|
1305
|
+
|
1306
|
+
|
1307
|
+
|
1308
|
+
|
1309
|
+
|
1310
|
+
//
|
1311
|
+
// Draws the labelsAbove
|
1312
|
+
//
|
1313
|
+
this.drawLabelsAbove = function ()
|
1314
|
+
{
|
1315
|
+
// Go through the above labels
|
1316
|
+
if (prop.labelsAbove) {
|
1317
|
+
|
1318
|
+
for (var dataset=0; dataset<this.coords.length; ++dataset) {
|
1319
|
+
for (var i=0; i<this.coords[dataset].length; ++i) {
|
1320
|
+
|
1321
|
+
var str = RG.SVG.numberFormat({
|
1322
|
+
object: this,
|
1323
|
+
num: this.data[dataset][i].toFixed(prop.labelsAboveDecimals ),
|
1324
|
+
prepend: typeof prop.labelsAboveUnitsPre === 'string' ? prop.labelsAboveUnitsPre : null,
|
1325
|
+
append: typeof prop.labelsAboveUnitsPost === 'string' ? prop.labelsAboveUnitsPost : null,
|
1326
|
+
point: typeof prop.labelsAbovePoint === 'string' ? prop.labelsAbovePoint : null,
|
1327
|
+
thousand: typeof prop.labelsAboveThousand === 'string' ? prop.labelsAboveThousand : null,
|
1328
|
+
formatter: typeof prop.labelsAboveFormatter === 'function' ? prop.labelsAboveFormatter : null
|
1329
|
+
});
|
1330
|
+
|
1331
|
+
RG.SVG.text({
|
1332
|
+
object: this,
|
1333
|
+
text: str,
|
1334
|
+
x: parseFloat(this.coords[dataset][i][0]) + prop.labelsAboveOffsetx,
|
1335
|
+
y: parseFloat(this.coords[dataset][i][1]) + prop.labelsAboveOffsety,
|
1336
|
+
halign: prop.labelsAboveHalign,
|
1337
|
+
valign: prop.labelsAboveValign,
|
1338
|
+
font: prop.labelsAboveFont || prop.textFont,
|
1339
|
+
size: prop.labelsAboveSize || prop.textSize,
|
1340
|
+
bold: prop.labelsAboveBold || prop.textBold,
|
1341
|
+
italic: prop.labelsAboveItalic || prop.textItalic,
|
1342
|
+
color: prop.labelsAboveColor || prop.textColor,
|
1343
|
+
background: prop.labelsAboveBackground || null,
|
1344
|
+
padding: prop.labelsAboveBackgroundPadding || 0
|
1345
|
+
});
|
1346
|
+
}
|
1347
|
+
}
|
1348
|
+
}
|
1349
|
+
};
|
1350
|
+
|
1351
|
+
|
1352
|
+
|
1353
|
+
|
1354
|
+
|
1355
|
+
|
1356
|
+
|
1357
|
+
|
1358
|
+
/**
|
1359
|
+
* Using a function to add events makes it easier to facilitate method
|
1360
|
+
* chaining
|
1361
|
+
*
|
1362
|
+
* @param string type The type of even to add
|
1363
|
+
* @param function func
|
1364
|
+
*/
|
1365
|
+
this.on = function (type, func)
|
1366
|
+
{
|
1367
|
+
if (type.substr(0,2) !== 'on') {
|
1368
|
+
type = 'on' + type;
|
1369
|
+
}
|
1370
|
+
|
1371
|
+
RG.SVG.addCustomEventListener(this, type, func);
|
1372
|
+
|
1373
|
+
return this;
|
1374
|
+
};
|
1375
|
+
|
1376
|
+
|
1377
|
+
|
1378
|
+
|
1379
|
+
|
1380
|
+
|
1381
|
+
|
1382
|
+
|
1383
|
+
//
|
1384
|
+
// Used in chaining. Runs a function there and then - not waiting for
|
1385
|
+
// the events to fire (eg the onbeforedraw event)
|
1386
|
+
//
|
1387
|
+
// @param function func The function to execute
|
1388
|
+
//
|
1389
|
+
this.exec = function (func)
|
1390
|
+
{
|
1391
|
+
func(this);
|
1392
|
+
|
1393
|
+
return this;
|
1394
|
+
};
|
1395
|
+
|
1396
|
+
|
1397
|
+
|
1398
|
+
|
1399
|
+
|
1400
|
+
|
1401
|
+
|
1402
|
+
|
1403
|
+
//
|
1404
|
+
// A trace effect
|
1405
|
+
//
|
1406
|
+
// @param object Options to give to the effect
|
1407
|
+
// @param function A function to call when the effect has completed
|
1408
|
+
//
|
1409
|
+
this.trace = function ()
|
1410
|
+
{
|
1411
|
+
var opt = arguments[0] || {},
|
1412
|
+
frame = 1,
|
1413
|
+
frames = opt.frames || 60,
|
1414
|
+
obj = this;
|
1415
|
+
|
1416
|
+
this.isTrace = true;
|
1417
|
+
|
1418
|
+
this.draw();
|
1419
|
+
|
1420
|
+
// Create the clip area
|
1421
|
+
var clipPath = RG.SVG.create({
|
1422
|
+
svg: this.svg,
|
1423
|
+
parent: this.defs,
|
1424
|
+
type: 'clipPath',
|
1425
|
+
attr: {
|
1426
|
+
id: 'trace-effect-clip'
|
1427
|
+
}
|
1428
|
+
});
|
1429
|
+
|
1430
|
+
var clipPathRect = RG.SVG.create({
|
1431
|
+
svg: this.svg,
|
1432
|
+
parent: clipPath,
|
1433
|
+
type: 'rect',
|
1434
|
+
attr: {
|
1435
|
+
x: 0,
|
1436
|
+
y: 0,
|
1437
|
+
width: 0,
|
1438
|
+
height: this.height
|
1439
|
+
}
|
1440
|
+
});
|
1441
|
+
|
1442
|
+
|
1443
|
+
var iterator = function ()
|
1444
|
+
{
|
1445
|
+
var width = (frame++) / frames * obj.width;
|
1446
|
+
|
1447
|
+
clipPathRect.setAttribute("width", width);
|
1448
|
+
|
1449
|
+
if (frame <= frames) {
|
1450
|
+
RG.SVG.FX.update(iterator);
|
1451
|
+
} else if (opt.callback) {
|
1452
|
+
(opt.callback)(obj);
|
1453
|
+
}
|
1454
|
+
};
|
1455
|
+
|
1456
|
+
iterator();
|
1457
|
+
|
1458
|
+
return this;
|
1459
|
+
};
|
1460
|
+
|
1461
|
+
|
1462
|
+
|
1463
|
+
|
1464
|
+
|
1465
|
+
|
1466
|
+
|
1467
|
+
|
1468
|
+
//
|
1469
|
+
// Set the options that the user has provided
|
1470
|
+
//
|
1471
|
+
for (i in conf.options) {
|
1472
|
+
if (typeof i === 'string') {
|
1473
|
+
this.set(i, conf.options[i]);
|
1474
|
+
}
|
1475
|
+
}
|
1476
|
+
}
|
1477
|
+
|
1478
|
+
|
1479
|
+
|
1480
|
+
return this;
|
1481
|
+
|
1482
|
+
|
1483
|
+
|
1484
|
+
|
1485
|
+
// End module pattern
|
1486
|
+
})(window, document);
|