highcharts-rails 5.0.10 → 5.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (25) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.markdown +48 -0
  3. data/app/assets/javascripts/highcharts.js +2395 -1517
  4. data/app/assets/javascripts/highcharts/highcharts-3d.js +212 -116
  5. data/app/assets/javascripts/highcharts/highcharts-more.js +17 -11
  6. data/app/assets/javascripts/highcharts/modules/accessibility.js +29 -16
  7. data/app/assets/javascripts/highcharts/modules/annotations.js +3 -4
  8. data/app/assets/javascripts/highcharts/modules/boost.js +392 -356
  9. data/app/assets/javascripts/highcharts/modules/broken-axis.js +42 -17
  10. data/app/assets/javascripts/highcharts/modules/data.js +6 -6
  11. data/app/assets/javascripts/highcharts/modules/drilldown.js +54 -27
  12. data/app/assets/javascripts/highcharts/modules/exporting.js +125 -102
  13. data/app/assets/javascripts/highcharts/modules/funnel.js +17 -9
  14. data/app/assets/javascripts/highcharts/modules/grid-axis.js +1 -1
  15. data/app/assets/javascripts/highcharts/modules/heatmap.js +12 -2
  16. data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +1 -1
  17. data/app/assets/javascripts/highcharts/modules/offline-exporting.js +12 -4
  18. data/app/assets/javascripts/highcharts/modules/overlapping-datalabels.js +1 -1
  19. data/app/assets/javascripts/highcharts/modules/series-label.js +1 -1
  20. data/app/assets/javascripts/highcharts/modules/solid-gauge.js +2 -2
  21. data/app/assets/javascripts/highcharts/modules/stock.js +182 -101
  22. data/app/assets/javascripts/highcharts/modules/treemap.js +4 -7
  23. data/app/assets/javascripts/highcharts/modules/xrange-series.js +1 -1
  24. data/lib/highcharts/version.rb +1 -1
  25. metadata +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.10 (2017-03-31)
2
+ * @license Highcharts JS v5.0.11 (2017-05-04)
3
3
  *
4
4
  * (c) 2009-2017 Torstein Honsi
5
5
  *
@@ -169,17 +169,14 @@
169
169
  length = 0,
170
170
  inBrk,
171
171
  repeat,
172
- brk,
173
172
  min = axis.userMin || axis.min,
174
173
  max = axis.userMax || axis.max,
175
174
  pointRangePadding = pick(axis.pointRangePadding, 0),
176
175
  start,
177
- i,
178
- j;
176
+ i;
179
177
 
180
178
  // Min & max check (#4247)
181
- for (i in breaks) {
182
- brk = breaks[i];
179
+ each(breaks, function(brk) {
183
180
  repeat = brk.repeat || Infinity;
184
181
  if (axis.isInBreak(brk, min)) {
185
182
  min += (brk.to % repeat) - (min % repeat);
@@ -187,11 +184,10 @@
187
184
  if (axis.isInBreak(brk, max)) {
188
185
  max -= (max % repeat) - (brk.from % repeat);
189
186
  }
190
- }
187
+ });
191
188
 
192
189
  // Construct an array holding all breaks in the axis
193
- for (i in breaks) {
194
- brk = breaks[i];
190
+ each(breaks, function(brk) {
195
191
  start = brk.from;
196
192
  repeat = brk.repeat || Infinity;
197
193
 
@@ -202,18 +198,18 @@
202
198
  start += repeat;
203
199
  }
204
200
 
205
- for (j = start; j < max; j += repeat) {
201
+ for (i = start; i < max; i += repeat) {
206
202
  breakArrayT.push({
207
- value: j,
203
+ value: i,
208
204
  move: 'in'
209
205
  });
210
206
  breakArrayT.push({
211
- value: j + (brk.to - brk.from),
207
+ value: i + (brk.to - brk.from),
212
208
  move: 'out',
213
209
  size: brk.breakSize
214
210
  });
215
211
  }
216
- }
212
+ });
217
213
 
218
214
  breakArrayT.sort(function(a, b) {
219
215
  var ret;
@@ -229,8 +225,7 @@
229
225
  inBrk = 0;
230
226
  start = min;
231
227
 
232
- for (i in breakArrayT) {
233
- brk = breakArrayT[i];
228
+ each(breakArrayT, function(brk) {
234
229
  inBrk += (brk.move === 'in' ? 1 : -1);
235
230
 
236
231
  if (inBrk === 1 && brk.move === 'in') {
@@ -244,7 +239,7 @@
244
239
  });
245
240
  length += brk.value - start - (brk.size || 0);
246
241
  }
247
- }
242
+ });
248
243
 
249
244
  axis.breakArray = breakArray;
250
245
 
@@ -256,7 +251,7 @@
256
251
 
257
252
  if (axis.options.staticScale) {
258
253
  axis.transA = axis.options.staticScale;
259
- } else {
254
+ } else if (axis.unitLength) {
260
255
  axis.transA *= (max - axis.min + pointRangePadding) /
261
256
  axis.unitLength;
262
257
  }
@@ -343,6 +338,36 @@
343
338
  });
344
339
  };
345
340
 
341
+
342
+ /**
343
+ * Extend getGraphPath by identifying gaps in the data so that we can draw a gap
344
+ * in the line or area. This was moved from ordinal axis module to broken axis
345
+ * module as of #5045.
346
+ */
347
+ H.Series.prototype.gappedPath = function() {
348
+ var gapSize = this.options.gapSize,
349
+ points = this.points.slice(),
350
+ i = points.length - 1;
351
+
352
+ if (gapSize && i > 0) { // #5008
353
+
354
+ // extension for ordinal breaks
355
+ while (i--) {
356
+ if (points[i + 1].x - points[i].x > this.closestPointRange * gapSize) {
357
+ points.splice( // insert after this one
358
+ i + 1,
359
+ 0, {
360
+ isNull: true
361
+ }
362
+ );
363
+ }
364
+ }
365
+ }
366
+
367
+ // Call base method
368
+ return this.getGraphPath(points);
369
+ };
370
+
346
371
  wrap(H.seriesTypes.column.prototype, 'drawPoints', drawPointsWrapped);
347
372
  wrap(H.Series.prototype, 'drawPoints', drawPointsWrapped);
348
373
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.10 (2017-03-31)
2
+ * @license Highcharts JS v5.0.11 (2017-05-04)
3
3
  * Data module
4
4
  *
5
5
  * (c) 2012-2017 Torstein Honsi
@@ -29,6 +29,7 @@
29
29
  var win = Highcharts.win,
30
30
  doc = win.document,
31
31
  each = Highcharts.each,
32
+ objectEach = Highcharts.objectEach,
32
33
  pick = Highcharts.pick,
33
34
  inArray = Highcharts.inArray,
34
35
  isNumber = Highcharts.isNumber,
@@ -118,7 +119,6 @@
118
119
  // the mapping options.
119
120
  each((options && options.seriesMapping) || [], function(mapping) {
120
121
  var builder = new SeriesBuilder(),
121
- name,
122
122
  numberOfValueColumnsNeeded = individualCounts[seriesIndex] || getValueCount(globalType),
123
123
  seriesArr = (chartOptions && chartOptions.series) || [],
124
124
  series = seriesArr[seriesIndex] || {},
@@ -129,11 +129,11 @@
129
129
  builder.addColumnReader(mapping.x, 'x');
130
130
 
131
131
  // Add all column mappings
132
- for (name in mapping) {
133
- if (mapping.hasOwnProperty(name) && name !== 'x') {
134
- builder.addColumnReader(mapping[name], name);
132
+ objectEach(mapping, function(val, name) {
133
+ if (name !== 'x') {
134
+ builder.addColumnReader(val, name);
135
135
  }
136
- }
136
+ });
137
137
 
138
138
  // Add missing columns
139
139
  for (i = 0; i < numberOfValueColumnsNeeded; i++) {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.10 (2017-03-31)
2
+ * @license Highcharts JS v5.0.11 (2017-05-04)
3
3
  * Highcharts Drilldown module
4
4
  *
5
5
  * Author: Torstein Honsi
@@ -30,6 +30,7 @@
30
30
  each = H.each,
31
31
  extend = H.extend,
32
32
  format = H.format,
33
+ objectEach = H.objectEach,
33
34
  pick = H.pick,
34
35
  wrap = H.wrap,
35
36
  Chart = H.Chart,
@@ -133,8 +134,26 @@
133
134
  });
134
135
  };
135
136
 
136
- Chart.prototype.addSeriesAsDrilldown = function(point, ddOptions) {
137
- this.addSingleSeriesAsDrilldown(point, ddOptions);
137
+ /**
138
+ * Add a series to the chart as drilldown from a specific point in the parent
139
+ * series. This method is used for async drilldown, when clicking a point in a
140
+ * series should result in loading and displaying a more high-resolution series.
141
+ * When not async, the setup is simpler using the {@link
142
+ * https://api.highcharts.com/highcharts/drilldown.series|drilldown.series}
143
+ * options structure.
144
+ *
145
+ * @memberOf Highcharts.Chart
146
+ * @function #addSeriesAsDrilldown
147
+ *
148
+ * @param {Highcharts.Point} point
149
+ * The point from which the drilldown will start.
150
+ * @param {SeriesOptions} options
151
+ * The series options for the new, detailed series.
152
+ *
153
+ * @sample highcharts/drilldown/async/ Async drilldown
154
+ */
155
+ Chart.prototype.addSeriesAsDrilldown = function(point, options) {
156
+ this.addSingleSeriesAsDrilldown(point, options);
138
157
  this.applyDrilldown();
139
158
  };
140
159
  Chart.prototype.addSingleSeriesAsDrilldown = function(point, ddOptions) {
@@ -299,6 +318,13 @@
299
318
  }
300
319
  };
301
320
 
321
+ /**
322
+ * When the chart is drilled down to a child series, calling `chart.drillUp()`
323
+ * will drill up to the parent series.
324
+ *
325
+ * @memberOf Highcharts.Chart
326
+ * @name #drillUp
327
+ */
302
328
  Chart.prototype.drillUp = function() {
303
329
  var chart = this,
304
330
  drilldownLevels = chart.drilldownLevels,
@@ -511,6 +537,9 @@
511
537
  ColumnSeries.prototype.animateDrillupFrom = function(level) {
512
538
  var animationOptions = this.chart.options.drilldown.animation,
513
539
  group = this.group,
540
+ // For 3d column series all columns are added to one group
541
+ // so we should not delete the whole group. #5297
542
+ removeGroup = group !== this.chart.seriesGroup,
514
543
  series = this;
515
544
 
516
545
  // Cancel mouse events on the series group (#2787)
@@ -520,14 +549,16 @@
520
549
  }
521
550
  });
522
551
 
552
+ if (removeGroup) {
553
+ delete this.group;
554
+ }
523
555
 
524
- delete this.group;
525
556
  each(this.points, function(point) {
526
557
  var graphic = point.graphic,
527
558
  animateTo = level.shapeArgs,
528
559
  complete = function() {
529
560
  graphic.destroy();
530
- if (group) {
561
+ if (group && removeGroup) {
531
562
  group = group.destroy();
532
563
  }
533
564
  };
@@ -640,15 +671,11 @@
640
671
  * Drill down to a given category. This is the same as clicking on an axis label.
641
672
  */
642
673
  H.Axis.prototype.drilldownCategory = function(x, e) {
643
- var key,
644
- point,
645
- ddPointsX = this.getDDPoints(x);
646
- for (key in ddPointsX) {
647
- point = ddPointsX[key];
674
+ objectEach(this.getDDPoints(x), function(point) {
648
675
  if (point && point.series && point.series.visible && point.doDrilldown) { // #3197
649
676
  point.doDrilldown(true, x, e);
650
677
  }
651
- }
678
+ });
652
679
  this.chart.applyDrilldown();
653
680
  };
654
681
 
@@ -787,26 +814,26 @@
787
814
  });
788
815
 
789
816
  // Mark the trackers with a pointer
790
- var type,
791
- drawTrackerWrapper = function(proceed) {
792
- proceed.call(this);
793
- each(this.points, function(point) {
794
- if (point.drilldown && point.graphic) {
795
- point.graphic.addClass('highcharts-drilldown-point');
817
+ var drawTrackerWrapper = function(proceed) {
818
+ proceed.call(this);
819
+ each(this.points, function(point) {
820
+ if (point.drilldown && point.graphic) {
821
+ point.graphic.addClass('highcharts-drilldown-point');
796
822
 
797
823
 
798
- point.graphic.css({
799
- cursor: 'pointer'
800
- });
824
+ point.graphic.css({
825
+ cursor: 'pointer'
826
+ });
801
827
 
802
- }
803
- });
804
- };
805
- for (type in seriesTypes) {
806
- if (seriesTypes[type].prototype.supportsDrilldown) {
807
- wrap(seriesTypes[type].prototype, 'drawTracker', drawTrackerWrapper);
828
+ }
829
+ });
830
+ };
831
+
832
+ objectEach(seriesTypes, function(seriesType) {
833
+ if (seriesType.prototype.supportsDrilldown) {
834
+ wrap(seriesType.prototype, 'drawTracker', drawTrackerWrapper);
808
835
  }
809
- }
836
+ });
810
837
 
811
838
  }(Highcharts));
812
839
  }));
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.10 (2017-03-31)
2
+ * @license Highcharts JS v5.0.11 (2017-05-04)
3
3
  * Exporting module
4
4
  *
5
5
  * (c) 2010-2017 Torstein Honsi
@@ -38,6 +38,7 @@
38
38
  merge = H.merge,
39
39
  pick = H.pick,
40
40
  each = H.each,
41
+ objectEach = H.objectEach,
41
42
  extend = H.extend,
42
43
  isTouchDevice = H.isTouchDevice,
43
44
  win = H.win,
@@ -122,75 +123,47 @@
122
123
  symbol: 'menu',
123
124
  _titleKey: 'contextButtonTitle',
124
125
  menuItems: [{
125
- textKey: 'printChart',
126
- onclick: function() {
127
- this.print();
128
- }
129
- }, {
130
- separator: true
131
- }, {
132
- textKey: 'downloadPNG',
133
- onclick: function() {
134
- this.exportChart();
135
- }
136
- }, {
137
- textKey: 'downloadJPEG',
138
- onclick: function() {
139
- this.exportChart({
140
- type: 'image/jpeg'
141
- });
142
- }
143
- }, {
144
- textKey: 'downloadPDF',
145
- onclick: function() {
146
- this.exportChart({
147
- type: 'application/pdf'
148
- });
149
- }
150
- }, {
151
- textKey: 'downloadSVG',
152
- onclick: function() {
153
- this.exportChart({
154
- type: 'image/svg+xml'
155
- });
156
- }
126
+ textKey: 'printChart',
127
+ onclick: function() {
128
+ this.print();
157
129
  }
158
- // Enable this block to add "View SVG" to the dropdown menu
159
- /*
160
- ,{
161
-
162
- text: 'View SVG Image',
163
- onclick: function () {
164
- var div = doc.createElement('div');
165
- div.innerHTML = this.getSVGForExport();
166
-
167
- this.renderTo.parentNode.appendChild(div);
168
- }
169
- }, {
170
-
171
- text: 'View SVG Source',
172
- onclick: function () {
173
- var pre = doc.createElement('pre');
174
- pre.innerHTML = this.getSVGForExport()
175
- .replace(/</g, '\n&lt;')
176
- .replace(/>/g, '&gt;');
177
-
178
- this.renderTo.parentNode.appendChild(pre);
179
- }
130
+ }, {
131
+ separator: true
132
+ }, {
133
+ textKey: 'downloadPNG',
134
+ onclick: function() {
135
+ this.exportChart();
136
+ }
137
+ }, {
138
+ textKey: 'downloadJPEG',
139
+ onclick: function() {
140
+ this.exportChart({
141
+ type: 'image/jpeg'
142
+ });
143
+ }
144
+ }, {
145
+ textKey: 'downloadPDF',
146
+ onclick: function() {
147
+ this.exportChart({
148
+ type: 'application/pdf'
149
+ });
150
+ }
151
+ }, {
152
+ textKey: 'downloadSVG',
153
+ onclick: function() {
154
+ this.exportChart({
155
+ type: 'image/svg+xml'
156
+ });
180
157
  }
181
- // */
182
- ]
158
+ }]
183
159
  }
184
160
  }
185
161
  };
186
162
 
187
163
  // Add the H.post utility
188
164
  H.post = function(url, data, formAttributes) {
189
- var name,
190
- form;
191
-
192
165
  // create the form
193
- form = createElement('form', merge({
166
+ var form = createElement('form', merge({
194
167
  method: 'post',
195
168
  action: url,
196
169
  enctype: 'multipart/form-data'
@@ -199,13 +172,13 @@
199
172
  }, doc.body);
200
173
 
201
174
  // add the data
202
- for (name in data) {
175
+ objectEach(data, function(val, name) {
203
176
  createElement('input', {
204
177
  type: 'hidden',
205
178
  name: name,
206
- value: data[name]
179
+ value: val
207
180
  }, null, form);
208
- }
181
+ });
209
182
 
210
183
  // submit
211
184
  form.submit();
@@ -214,7 +187,7 @@
214
187
  discardElement(form);
215
188
  };
216
189
 
217
- extend(Chart.prototype, {
190
+ extend(Chart.prototype, /** @lends Highcharts.Chart.prototype */ {
218
191
 
219
192
  /**
220
193
  * A collection of fixes on the produced SVG to account for expando properties,
@@ -290,13 +263,17 @@
290
263
  /**
291
264
  * Return an SVG representation of the chart.
292
265
  *
293
- * @param additionalOptions {Object} Additional chart options for the
294
- * generated SVG representation. For collections like `xAxis`, `yAxis` or
295
- * `series`, the additional options is either merged in to the orininal
296
- * item of the same `id`, or to the first item if a commin id is not
297
- * found.
266
+ * @param chartOptions {Options}
267
+ * Additional chart options for the generated SVG representation.
268
+ * For collections like `xAxis`, `yAxis` or `series`, the additional
269
+ * options is either merged in to the orininal item of the same
270
+ * `id`, or to the first item if a common id is not found.
271
+ * @return {String}
272
+ * The SVG representation of the rendered chart.
273
+ * @sample highcharts/members/chart-getsvg/
274
+ * View the SVG from a button
298
275
  */
299
- getSVG: function(additionalOptions) {
276
+ getSVG: function(chartOptions) {
300
277
  var chart = this,
301
278
  chartCopy,
302
279
  sandbox,
@@ -306,7 +283,7 @@
306
283
  sourceHeight,
307
284
  cssWidth,
308
285
  cssHeight,
309
- options = merge(chart.options, additionalOptions); // copy the options and add extra options
286
+ options = merge(chart.options, chartOptions); // copy the options and add extra options
310
287
 
311
288
 
312
289
  // IE compatibility hack for generating SVG content that it doesn't really understand
@@ -374,11 +351,11 @@
374
351
  chartCopy = new H.Chart(options, chart.callback);
375
352
 
376
353
  // Axis options and series options (#2022, #3900, #5982)
377
- if (additionalOptions) {
354
+ if (chartOptions) {
378
355
  each(['xAxis', 'yAxis', 'series'], function(coll) {
379
356
  var collOptions = {};
380
- if (additionalOptions[coll]) {
381
- collOptions[coll] = additionalOptions[coll];
357
+ if (chartOptions[coll]) {
358
+ collOptions[coll] = chartOptions[coll];
382
359
  chartCopy.update(collOptions);
383
360
  }
384
361
  });
@@ -431,30 +408,61 @@
431
408
  },
432
409
 
433
410
  /**
434
- * Submit the SVG representation of the chart to the server
435
- * @param {Object} options Exporting options. Possible members are url, type, width and formAttributes.
436
- * @param {Object} chartOptions Additional chart options for the SVG representation of the chart
411
+ * Exporting module required. Submit an SVG version of the chart to a server
412
+ * along with some parameters for conversion.
413
+ * @param {Object} exportingOptions
414
+ * Exporting options in addition to those defined in {@link
415
+ * https://api.highcharts.com/highcharts/exporting|exporting}.
416
+ * @param {String} exportingOptions.filename
417
+ * The file name for the export without extension.
418
+ * @param {String} exportingOptions.url
419
+ * The URL for the server module to do the conversion.
420
+ * @param {Number} exportingOptions.width
421
+ * The width of the PNG or JPG image generated on the server.
422
+ * @param {String} exportingOptions.type
423
+ * The MIME type of the converted image.
424
+ * @param {Number} exportingOptions.sourceWidth
425
+ * The pixel width of the source (in-page) chart.
426
+ * @param {Number} exportingOptions.sourceHeight
427
+ * The pixel height of the source (in-page) chart.
428
+ * @param {Options} chartOptions
429
+ * Additional chart options for the exported chart. For example a
430
+ * different background color can be added here, or `dataLabels`
431
+ * for export only.
432
+ *
433
+ * @sample highcharts/members/chart-exportchart/
434
+ * Export with no options
435
+ * @sample highcharts/members/chart-exportchart-filename/
436
+ * PDF type and custom filename
437
+ * @sample highcharts/members/chart-exportchart-custom-background/
438
+ * Different chart background in export
437
439
  */
438
- exportChart: function(options, chartOptions) {
440
+ exportChart: function(exportingOptions, chartOptions) {
439
441
 
440
- var svg = this.getSVGForExport(options, chartOptions);
442
+ var svg = this.getSVGForExport(exportingOptions, chartOptions);
441
443
 
442
444
  // merge the options
443
- options = merge(this.options.exporting, options);
445
+ exportingOptions = merge(this.options.exporting, exportingOptions);
444
446
 
445
447
  // do the post
446
- H.post(options.url, {
447
- filename: options.filename || 'chart',
448
- type: options.type,
449
- width: options.width || 0, // IE8 fails to post undefined correctly, so use 0
450
- scale: options.scale,
448
+ H.post(exportingOptions.url, {
449
+ filename: exportingOptions.filename || 'chart',
450
+ type: exportingOptions.type,
451
+ width: exportingOptions.width || 0, // IE8 fails to post undefined correctly, so use 0
452
+ scale: exportingOptions.scale,
451
453
  svg: svg
452
- }, options.formAttributes);
454
+ }, exportingOptions.formAttributes);
453
455
 
454
456
  },
455
457
 
456
458
  /**
457
- * Print the chart
459
+ * Exporting module required. Clears away other elements in the page and
460
+ * prints the chart as it is displayed. By default, when the exporting
461
+ * module is enabled, a context button with a drop down menu in the upper
462
+ * right corner accesses this function.
463
+ *
464
+ * @sample highcharts/members/chart-print/
465
+ * Print from a HTML button
458
466
  */
459
467
  print: function() {
460
468
 
@@ -855,28 +863,28 @@
855
863
 
856
864
  // Add the buttons on chart load
857
865
  Chart.prototype.renderExporting = function() {
858
- var n,
859
- exportingOptions = this.options.exporting,
866
+ var chart = this,
867
+ exportingOptions = chart.options.exporting,
860
868
  buttons = exportingOptions.buttons,
861
- isDirty = this.isDirtyExporting || !this.exportSVGElements;
869
+ isDirty = chart.isDirtyExporting || !chart.exportSVGElements;
862
870
 
863
- this.buttonOffset = 0;
864
- if (this.isDirtyExporting) {
865
- this.destroyExport();
871
+ chart.buttonOffset = 0;
872
+ if (chart.isDirtyExporting) {
873
+ chart.destroyExport();
866
874
  }
867
875
 
868
876
  if (isDirty && exportingOptions.enabled !== false) {
869
- this.exportEvents = [];
877
+ chart.exportEvents = [];
870
878
 
871
- for (n in buttons) {
872
- this.addButton(buttons[n]);
873
- }
879
+ objectEach(buttons, function(button) {
880
+ chart.addButton(button);
881
+ });
874
882
 
875
- this.isDirtyExporting = false;
883
+ chart.isDirtyExporting = false;
876
884
  }
877
885
 
878
886
  // Destroy the export elements at chart destroy
879
- addEvent(this, 'destroy', this.destroyExport);
887
+ addEvent(chart, 'destroy', chart.destroyExport);
880
888
  };
881
889
 
882
890
  Chart.prototype.callbacks.push(function(chart) {
@@ -908,14 +916,29 @@
908
916
  // testing of export
909
917
  /*
910
918
  if (!chart.renderer.forExport) {
911
- var button = doc.createElement('button');
912
- button.innerHTML = 'View exported SVG';
919
+ var button;
920
+
921
+ // View SVG Image
922
+ button = doc.createElement('button');
923
+ button.innerHTML = 'View SVG Image';
913
924
  chart.renderTo.parentNode.appendChild(button);
914
925
  button.onclick = function () {
915
926
  var div = doc.createElement('div');
916
927
  div.innerHTML = chart.getSVGForExport();
917
928
  chart.renderTo.parentNode.appendChild(div);
918
929
  };
930
+
931
+ // View SVG Source
932
+ button = doc.createElement('button');
933
+ button.innerHTML = 'View SVG Source';
934
+ chart.renderTo.parentNode.appendChild(button);
935
+ button.onclick = function () {
936
+ var pre = doc.createElement('pre');
937
+ pre.innerHTML = chart.getSVGForExport()
938
+ .replace(/</g, '\n&lt;')
939
+ .replace(/>/g, '&gt;');
940
+ chart.renderTo.parentNode.appendChild(pre);
941
+ };
919
942
  }
920
943
  // */
921
944
  });