contour 1.1.1 → 1.1.2.pre

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. data/CHANGELOG.rdoc +11 -0
  2. data/app/assets/images/twitter-bootstrap/v2.2.1/glyphicons-halflings-white.png +0 -0
  3. data/app/assets/images/twitter-bootstrap/v2.2.1/glyphicons-halflings.png +0 -0
  4. data/app/assets/javascripts/contour.js +3 -3
  5. data/app/assets/javascripts/external/{exporting-2.1.9.src.js → exporting-2.3.3.src.js} +736 -758
  6. data/app/assets/javascripts/external/highcharts-2.3.3.src.js +15111 -0
  7. data/app/assets/javascripts/twitter-bootstrap/{v2.1.1 → v2.2.1}/bootstrap.js +105 -107
  8. data/app/assets/stylesheets/bootstrap-base-overrides.css +6 -6
  9. data/app/assets/stylesheets/contour.css +2 -2
  10. data/app/assets/stylesheets/twitter-bootstrap/{v2.1.1 → v2.2.1}/bootstrap-responsive.css +33 -3
  11. data/app/assets/stylesheets/twitter-bootstrap/{v2.1.1 → v2.2.1}/bootstrap.css +377 -258
  12. data/app/views/contour/layouts/_per_page.html.erb +1 -1
  13. data/app/views/kaminari/contour-large/_first_page.html.erb +11 -0
  14. data/app/views/kaminari/contour-large/_gap.html.erb +8 -0
  15. data/app/views/kaminari/contour-large/_last_page.html.erb +11 -0
  16. data/app/views/kaminari/contour-large/_next_page.html.erb +11 -0
  17. data/app/views/kaminari/contour-large/_page.html.erb +12 -0
  18. data/app/views/kaminari/contour-large/_paginator.html.erb +25 -0
  19. data/app/views/kaminari/contour-large/_prev_page.html.erb +11 -0
  20. data/app/views/kaminari/contour-mini/_first_page.html.erb +11 -0
  21. data/app/views/kaminari/contour-mini/_gap.html.erb +8 -0
  22. data/app/views/kaminari/contour-mini/_last_page.html.erb +11 -0
  23. data/app/views/kaminari/contour-mini/_next_page.html.erb +11 -0
  24. data/app/views/kaminari/contour-mini/_page.html.erb +12 -0
  25. data/app/views/kaminari/contour-mini/_paginator.html.erb +25 -0
  26. data/app/views/kaminari/contour-mini/_prev_page.html.erb +11 -0
  27. data/app/views/kaminari/contour-small/_first_page.html.erb +11 -0
  28. data/app/views/kaminari/contour-small/_gap.html.erb +8 -0
  29. data/app/views/kaminari/contour-small/_last_page.html.erb +11 -0
  30. data/app/views/kaminari/contour-small/_next_page.html.erb +11 -0
  31. data/app/views/kaminari/contour-small/_page.html.erb +12 -0
  32. data/app/views/kaminari/contour-small/_paginator.html.erb +25 -0
  33. data/app/views/kaminari/contour-small/_prev_page.html.erb +11 -0
  34. data/app/views/kaminari/contour/_first_page.html.erb +11 -0
  35. data/app/views/kaminari/contour/_gap.html.erb +8 -0
  36. data/app/views/kaminari/contour/_last_page.html.erb +11 -0
  37. data/app/views/kaminari/contour/_next_page.html.erb +11 -0
  38. data/app/views/kaminari/contour/_page.html.erb +12 -0
  39. data/app/views/kaminari/contour/_paginator.html.erb +25 -0
  40. data/app/views/kaminari/contour/_prev_page.html.erb +11 -0
  41. data/contour.gemspec +4 -4
  42. data/lib/contour/version.rb +2 -2
  43. data/lib/generators/contour/scaffold/templates/_paginate.html.erb +1 -1
  44. data/test/dummy/db/test.sqlite3 +0 -0
  45. data/test/dummy/log/test.log +714 -0
  46. metadata +48 -18
  47. data/app/assets/javascripts/external/highcharts-2.1.9.src.js +0 -11454
@@ -1,3 +1,14 @@
1
+ == 1.1.2
2
+
3
+ * Enhancements
4
+ * Recommended Ruby bumped to 1.9.3-p327
5
+ * Updated Twitter Bootstrap to 2.2.1
6
+ * Updated HighCharts to 2.3.3
7
+ * Kaminari Pagination styling now provided, available themes:
8
+ * <%= paginate @items, theme: "contour[-large|-small|-mini]" %>
9
+ * Update Gem Dependencies
10
+ * rails 3.2.9, jquery-rails 2.1.4, omniauth-cas 1.0.0, omniauth-twitter 0.0.14
11
+
1
12
  == 1.1.1
2
13
 
3
14
  * Bug Fix
@@ -7,12 +7,12 @@
7
7
  //= require external/jquery-ui-1.8.22.custom.min.js
8
8
  //= require external/jquery.qtip.min.js
9
9
  //
10
- //= require twitter-bootstrap/v2.1.1/bootstrap
10
+ //= require twitter-bootstrap/v2.2.1/bootstrap
11
11
  //
12
12
  //= require twitter-bootstrap/bootstrap-scroll-modal
13
13
  //= require twitter-bootstrap/bootstrap
14
14
  //
15
- //= require external/highcharts-2.1.9.src.js
16
- //= require external/exporting-2.1.9.src.js
15
+ //= require external/highcharts-2.3.3.src.js
16
+ //= require external/exporting-2.3.3.src.js
17
17
  //
18
18
  //= require_tree .
@@ -1,758 +1,736 @@
1
- /**
2
- * @license Highcharts JS v2.1.9 (2011-11-11)
3
- * Exporting module
4
- *
5
- * (c) 2010-2011 Torstein Hønsi
6
- *
7
- * License: www.highcharts.com/license
8
- */
9
-
10
- // JSLint options:
11
- /*global Highcharts, document, window, Math, setTimeout */
12
-
13
- (function () { // encapsulate
14
-
15
- // create shortcuts
16
- var HC = Highcharts,
17
- Chart = HC.Chart,
18
- addEvent = HC.addEvent,
19
- removeEvent = HC.removeEvent,
20
- createElement = HC.createElement,
21
- discardElement = HC.discardElement,
22
- css = HC.css,
23
- merge = HC.merge,
24
- each = HC.each,
25
- extend = HC.extend,
26
- math = Math,
27
- mathMax = math.max,
28
- doc = document,
29
- win = window,
30
- hasTouch = doc.documentElement.ontouchstart !== undefined,
31
- M = 'M',
32
- L = 'L',
33
- DIV = 'div',
34
- HIDDEN = 'hidden',
35
- NONE = 'none',
36
- PREFIX = 'highcharts-',
37
- ABSOLUTE = 'absolute',
38
- PX = 'px',
39
- UNDEFINED,
40
- defaultOptions = HC.getOptions();
41
-
42
- // Add language
43
- extend(defaultOptions.lang, {
44
- downloadPNG: 'Download PNG image',
45
- downloadJPEG: 'Download JPEG image',
46
- downloadPDF: 'Download PDF document',
47
- downloadSVG: 'Download SVG vector image',
48
- exportButtonTitle: 'Export to raster or vector image',
49
- printButtonTitle: 'Print the chart'
50
- });
51
-
52
- // Buttons and menus are collected in a separate config option set called 'navigation'.
53
- // This can be extended later to add control buttons like zoom and pan right click menus.
54
- defaultOptions.navigation = {
55
- menuStyle: {
56
- border: '1px solid #A0A0A0',
57
- background: '#FFFFFF'
58
- },
59
- menuItemStyle: {
60
- padding: '0 5px',
61
- background: NONE,
62
- color: '#303030',
63
- fontSize: hasTouch ? '14px' : '11px'
64
- },
65
- menuItemHoverStyle: {
66
- background: '#4572A5',
67
- color: '#FFFFFF'
68
- },
69
-
70
- buttonOptions: {
71
- align: 'right',
72
- backgroundColor: {
73
- linearGradient: [0, 0, 0, 20],
74
- stops: [
75
- [0.4, '#F7F7F7'],
76
- [0.6, '#E3E3E3']
77
- ]
78
- },
79
- borderColor: '#B0B0B0',
80
- borderRadius: 3,
81
- borderWidth: 1,
82
- //enabled: true,
83
- height: 20,
84
- hoverBorderColor: '#909090',
85
- hoverSymbolFill: '#81A7CF',
86
- hoverSymbolStroke: '#4572A5',
87
- symbolFill: '#E0E0E0',
88
- //symbolSize: 12,
89
- symbolStroke: '#A0A0A0',
90
- //symbolStrokeWidth: 1,
91
- symbolX: 11.5,
92
- symbolY: 10.5,
93
- verticalAlign: 'top',
94
- width: 24,
95
- y: 10
96
- }
97
- };
98
-
99
-
100
-
101
- // Add the export related options
102
- defaultOptions.exporting = {
103
- //enabled: true,
104
- //filename: 'chart',
105
- type: 'image/png',
106
- url: 'http://export.highcharts.com/',
107
- width: 800,
108
- enableImages: false,
109
- buttons: {
110
- exportButton: {
111
- //enabled: true,
112
- symbol: 'exportIcon',
113
- x: -10,
114
- symbolFill: '#A8BF77',
115
- hoverSymbolFill: '#768F3E',
116
- _id: 'exportButton',
117
- _titleKey: 'exportButtonTitle',
118
- menuItems: [{
119
- textKey: 'downloadPNG',
120
- onclick: function () {
121
- this.exportChart();
122
- }
123
- }, {
124
- textKey: 'downloadJPEG',
125
- onclick: function () {
126
- this.exportChart({
127
- type: 'image/jpeg'
128
- });
129
- }
130
- }, {
131
- textKey: 'downloadPDF',
132
- onclick: function () {
133
- this.exportChart({
134
- type: 'application/pdf'
135
- });
136
- }
137
- }, {
138
- textKey: 'downloadSVG',
139
- onclick: function () {
140
- this.exportChart({
141
- type: 'image/svg+xml'
142
- });
143
- }
144
- }/*, {
145
- text: 'View SVG',
146
- onclick: function() {
147
- var svg = this.getSVG()
148
- .replace(/</g, '\n&lt;')
149
- .replace(/>/g, '&gt;');
150
-
151
- doc.body.innerHTML = '<pre>'+ svg +'</pre>';
152
- }
153
- }*/]
154
-
155
- },
156
- printButton: {
157
- //enabled: true,
158
- symbol: 'printIcon',
159
- x: -36,
160
- symbolFill: '#B5C9DF',
161
- hoverSymbolFill: '#779ABF',
162
- _id: 'printButton',
163
- _titleKey: 'printButtonTitle',
164
- onclick: function () {
165
- this.print();
166
- }
167
- }
168
- }
169
- };
170
-
171
-
172
-
173
- extend(Chart.prototype, {
174
- /**
175
- * Return an SVG representation of the chart
176
- *
177
- * @param additionalOptions {Object} Additional chart options for the generated SVG representation
178
- */
179
- getSVG: function (additionalOptions) {
180
- var chart = this,
181
- chartCopy,
182
- sandbox,
183
- svg,
184
- seriesOptions,
185
- config,
186
- pointOptions,
187
- pointMarker,
188
- options = merge(chart.options, additionalOptions); // copy the options and add extra options
189
-
190
- // IE compatibility hack for generating SVG content that it doesn't really understand
191
- if (!doc.createElementNS) {
192
- /*jslint unparam: true*//* allow unused parameter ns in function below */
193
- doc.createElementNS = function (ns, tagName) {
194
- var elem = doc.createElement(tagName);
195
- elem.getBBox = function () {
196
- return HC.Renderer.prototype.Element.prototype.getBBox.apply({ element: elem });
197
- };
198
- return elem;
199
- };
200
- /*jslint unparam: false*/
201
- }
202
-
203
- // create a sandbox where a new chart will be generated
204
- sandbox = createElement(DIV, null, {
205
- position: ABSOLUTE,
206
- top: '-9999em',
207
- width: chart.chartWidth + PX,
208
- height: chart.chartHeight + PX
209
- }, doc.body);
210
-
211
- // override some options
212
- extend(options.chart, {
213
- renderTo: sandbox,
214
- forExport: true
215
- });
216
- options.exporting.enabled = false; // hide buttons in print
217
-
218
- if (!options.exporting.enableImages) {
219
- options.chart.plotBackgroundImage = null; // the converter doesn't handle images
220
- }
221
-
222
- // prepare for replicating the chart
223
- options.series = [];
224
- each(chart.series, function (serie) {
225
- seriesOptions = serie.options;
226
-
227
- seriesOptions.animation = false; // turn off animation
228
- seriesOptions.showCheckbox = false;
229
- seriesOptions.visible = serie.visible;
230
-
231
- if (!options.exporting.enableImages) {
232
- // remove image markers
233
- if (seriesOptions && seriesOptions.marker && /^url\(/.test(seriesOptions.marker.symbol)) {
234
- seriesOptions.marker.symbol = 'circle';
235
- }
236
- }
237
-
238
- seriesOptions.data = [];
239
-
240
- each(serie.data, function (point) {
241
-
242
- // extend the options by those values that can be expressed in a number or array config
243
- config = point.config;
244
- pointOptions = {
245
- x: point.x,
246
- y: point.y,
247
- name: point.name
248
- };
249
-
250
- if (typeof config === 'object' && point.config && config.constructor !== Array) {
251
- extend(pointOptions, config);
252
- }
253
-
254
- pointOptions.visible = point.visible;
255
- seriesOptions.data.push(pointOptions); // copy fresh updated data
256
-
257
- if (!options.exporting.enableImages) {
258
- // remove image markers
259
- pointMarker = point.config && point.config.marker;
260
- if (pointMarker && /^url\(/.test(pointMarker.symbol)) {
261
- delete pointMarker.symbol;
262
- }
263
- }
264
- });
265
-
266
- options.series.push(seriesOptions);
267
- });
268
-
269
- // generate the chart copy
270
- chartCopy = new Highcharts.Chart(options);
271
-
272
- // reflect axis extremes in the export
273
- each(['xAxis', 'yAxis'], function (axisType) {
274
- each(chart[axisType], function (axis, i) {
275
- var axisCopy = chartCopy[axisType][i],
276
- extremes = axis.getExtremes(),
277
- userMin = extremes.userMin,
278
- userMax = extremes.userMax;
279
-
280
- if (userMin !== UNDEFINED || userMax !== UNDEFINED) {
281
- axisCopy.setExtremes(userMin, userMax, true, false);
282
- }
283
- });
284
- });
285
-
286
- // get the SVG from the container's innerHTML
287
- svg = chartCopy.container.innerHTML;
288
-
289
- // free up memory
290
- options = null;
291
- chartCopy.destroy();
292
- discardElement(sandbox);
293
-
294
- // sanitize
295
- svg = svg
296
- .replace(/zIndex="[^"]+"/g, '')
297
- .replace(/isShadow="[^"]+"/g, '')
298
- .replace(/symbolName="[^"]+"/g, '')
299
- .replace(/jQuery[0-9]+="[^"]+"/g, '')
300
- .replace(/isTracker="[^"]+"/g, '')
301
- .replace(/url\([^#]+#/g, 'url(#')
302
- .replace(/<svg /, '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
303
- .replace(/ href=/g, ' xlink:href=')
304
- /*.replace(/preserveAspectRatio="none">/g, 'preserveAspectRatio="none"/>')*/
305
- /* This fails in IE < 8
306
- .replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weight
307
- return s2 +'.'+ s3[0];
308
- })*/
309
-
310
- // Replace HTML entities, issue #347
311
- .replace(/&nbsp;/g, '\u00A0') // no-break space
312
- .replace(/&shy;/g, '\u00AD') // soft hyphen
313
-
314
- // IE specific
315
- .replace(/id=([^" >]+)/g, 'id="$1"')
316
- .replace(/class=([^" ]+)/g, 'class="$1"')
317
- .replace(/ transform /g, ' ')
318
- .replace(/:(path|rect)/g, '$1')
319
- .replace(/<img ([^>]*)>/gi, '<image $1 />')
320
- .replace(/<\/image>/g, '') // remove closing tags for images as they'll never have any content
321
- .replace(/<image ([^>]*)([^\/])>/gi, '<image $1$2 />') // closes image tags for firefox
322
- .replace(/width=(\d+)/g, 'width="$1"')
323
- .replace(/height=(\d+)/g, 'height="$1"')
324
- .replace(/hc-svg-href="/g, 'xlink:href="')
325
- .replace(/style="([^"]+)"/g, function (s) {
326
- return s.toLowerCase();
327
- });
328
-
329
- // IE9 beta bugs with innerHTML. Test again with final IE9.
330
- svg = svg.replace(/(url\(#highcharts-[0-9]+)&quot;/g, '$1')
331
- .replace(/&quot;/g, "'");
332
- if (svg.match(/ xmlns="/g).length === 2) {
333
- svg = svg.replace(/xmlns="[^"]+"/, '');
334
- }
335
-
336
- return svg;
337
- },
338
-
339
- /**
340
- * Submit the SVG representation of the chart to the server
341
- * @param {Object} options Exporting options. Possible members are url, type and width.
342
- * @param {Object} chartOptions Additional chart options for the SVG representation of the chart
343
- */
344
- exportChart: function (options, chartOptions) {
345
- var form,
346
- chart = this,
347
- svg = chart.getSVG(chartOptions);
348
-
349
- // merge the options
350
- options = merge(chart.options.exporting, options);
351
-
352
- // create the form
353
- form = createElement('form', {
354
- method: 'post',
355
- action: options.url
356
- }, {
357
- display: NONE
358
- }, doc.body);
359
-
360
- // add the values
361
- each(['filename', 'type', 'width', 'svg'], function (name) {
362
- createElement('input', {
363
- type: HIDDEN,
364
- name: name,
365
- value: {
366
- filename: options.filename || 'chart',
367
- type: options.type,
368
- width: options.width,
369
- svg: svg
370
- }[name]
371
- }, null, form);
372
- });
373
-
374
- // submit
375
- form.submit();
376
-
377
- // clean up
378
- discardElement(form);
379
- },
380
-
381
- /**
382
- * Print the chart
383
- */
384
- print: function () {
385
-
386
- var chart = this,
387
- container = chart.container,
388
- origDisplay = [],
389
- origParent = container.parentNode,
390
- body = doc.body,
391
- childNodes = body.childNodes;
392
-
393
- if (chart.isPrinting) { // block the button while in printing mode
394
- return;
395
- }
396
-
397
- chart.isPrinting = true;
398
-
399
- // hide all body content
400
- each(childNodes, function (node, i) {
401
- if (node.nodeType === 1) {
402
- origDisplay[i] = node.style.display;
403
- node.style.display = NONE;
404
- }
405
- });
406
-
407
- // pull out the chart
408
- body.appendChild(container);
409
-
410
- // print
411
- win.print();
412
-
413
- // allow the browser to prepare before reverting
414
- setTimeout(function () {
415
-
416
- // put the chart back in
417
- origParent.appendChild(container);
418
-
419
- // restore all body content
420
- each(childNodes, function (node, i) {
421
- if (node.nodeType === 1) {
422
- node.style.display = origDisplay[i];
423
- }
424
- });
425
-
426
- chart.isPrinting = false;
427
-
428
- }, 1000);
429
-
430
- },
431
-
432
- /**
433
- * Display a popup menu for choosing the export type
434
- *
435
- * @param {String} name An identifier for the menu
436
- * @param {Array} items A collection with text and onclicks for the items
437
- * @param {Number} x The x position of the opener button
438
- * @param {Number} y The y position of the opener button
439
- * @param {Number} width The width of the opener button
440
- * @param {Number} height The height of the opener button
441
- */
442
- contextMenu: function (name, items, x, y, width, height) {
443
- var chart = this,
444
- navOptions = chart.options.navigation,
445
- menuItemStyle = navOptions.menuItemStyle,
446
- chartWidth = chart.chartWidth,
447
- chartHeight = chart.chartHeight,
448
- cacheName = 'cache-' + name,
449
- menu = chart[cacheName],
450
- menuPadding = mathMax(width, height), // for mouse leave detection
451
- boxShadow = '3px 3px 10px #888',
452
- innerMenu,
453
- hide,
454
- menuStyle;
455
-
456
- // create the menu only the first time
457
- if (!menu) {
458
-
459
- // create a HTML element above the SVG
460
- chart[cacheName] = menu = createElement(DIV, {
461
- className: PREFIX + name
462
- }, {
463
- position: ABSOLUTE,
464
- zIndex: 1000,
465
- padding: menuPadding + PX
466
- }, chart.container);
467
-
468
- innerMenu = createElement(DIV, null,
469
- extend({
470
- MozBoxShadow: boxShadow,
471
- WebkitBoxShadow: boxShadow,
472
- boxShadow: boxShadow
473
- }, navOptions.menuStyle), menu);
474
-
475
- // hide on mouse out
476
- hide = function () {
477
- css(menu, { display: NONE });
478
- };
479
-
480
- addEvent(menu, 'mouseleave', hide);
481
-
482
-
483
- // create the items
484
- each(items, function (item) {
485
- if (item) {
486
- var div = createElement(DIV, {
487
- onmouseover: function () {
488
- css(this, navOptions.menuItemHoverStyle);
489
- },
490
- onmouseout: function () {
491
- css(this, menuItemStyle);
492
- },
493
- innerHTML: item.text || chart.options.lang[item.textKey]
494
- }, extend({
495
- cursor: 'pointer'
496
- }, menuItemStyle), innerMenu);
497
-
498
- div[hasTouch ? 'ontouchstart' : 'onclick'] = function () {
499
- hide();
500
- item.onclick.apply(chart, arguments);
501
- };
502
-
503
- // Keep references to menu divs to be able to destroy them
504
- chart.exportDivElements.push(div);
505
- }
506
- });
507
-
508
- // Keep references to menu and innerMenu div to be able to destroy them
509
- chart.exportDivElements.push(innerMenu, menu);
510
-
511
- chart.exportMenuWidth = menu.offsetWidth;
512
- chart.exportMenuHeight = menu.offsetHeight;
513
- }
514
-
515
- menuStyle = { display: 'block' };
516
-
517
- // if outside right, right align it
518
- if (x + chart.exportMenuWidth > chartWidth) {
519
- menuStyle.right = (chartWidth - x - width - menuPadding) + PX;
520
- } else {
521
- menuStyle.left = (x - menuPadding) + PX;
522
- }
523
- // if outside bottom, bottom align it
524
- if (y + height + chart.exportMenuHeight > chartHeight) {
525
- menuStyle.bottom = (chartHeight - y - menuPadding) + PX;
526
- } else {
527
- menuStyle.top = (y + height - menuPadding) + PX;
528
- }
529
-
530
- css(menu, menuStyle);
531
- },
532
-
533
- /**
534
- * Add the export button to the chart
535
- */
536
- addButton: function (options) {
537
- var chart = this,
538
- renderer = chart.renderer,
539
- btnOptions = merge(chart.options.navigation.buttonOptions, options),
540
- onclick = btnOptions.onclick,
541
- menuItems = btnOptions.menuItems,
542
- /*position = chart.getAlignment(btnOptions),
543
- buttonLeft = position.x,
544
- buttonTop = position.y,*/
545
- buttonWidth = btnOptions.width,
546
- buttonHeight = btnOptions.height,
547
- box,
548
- symbol,
549
- button,
550
- borderWidth = btnOptions.borderWidth,
551
- boxAttr = {
552
- stroke: btnOptions.borderColor
553
-
554
- },
555
- symbolAttr = {
556
- stroke: btnOptions.symbolStroke,
557
- fill: btnOptions.symbolFill
558
- };
559
-
560
- // Keeps references to the button elements
561
- if (!chart.exportDivElements) {
562
- chart.exportDivElements = [];
563
- chart.exportSVGElements = [];
564
- }
565
-
566
- if (btnOptions.enabled === false) {
567
- return;
568
- }
569
-
570
- // element to capture the click
571
- function revert() {
572
- symbol.attr(symbolAttr);
573
- box.attr(boxAttr);
574
- }
575
-
576
- // the box border
577
- box = renderer.rect(
578
- 0,
579
- 0,
580
- buttonWidth,
581
- buttonHeight,
582
- btnOptions.borderRadius,
583
- borderWidth
584
- )
585
- //.translate(buttonLeft, buttonTop) // to allow gradients
586
- .align(btnOptions, true)
587
- .attr(extend({
588
- fill: btnOptions.backgroundColor,
589
- 'stroke-width': borderWidth,
590
- zIndex: 19
591
- }, boxAttr)).add();
592
-
593
- // the invisible element to track the clicks
594
- button = renderer.rect(
595
- 0,
596
- 0,
597
- buttonWidth,
598
- buttonHeight,
599
- 0
600
- )
601
- .align(btnOptions)
602
- .attr({
603
- id: btnOptions._id,
604
- fill: 'rgba(255, 255, 255, 0.001)',
605
- title: chart.options.lang[btnOptions._titleKey],
606
- zIndex: 21
607
- }).css({
608
- cursor: 'pointer'
609
- })
610
- .on('mouseover', function () {
611
- symbol.attr({
612
- stroke: btnOptions.hoverSymbolStroke,
613
- fill: btnOptions.hoverSymbolFill
614
- });
615
- box.attr({
616
- stroke: btnOptions.hoverBorderColor
617
- });
618
- })
619
- .on('mouseout', revert)
620
- .on('click', revert)
621
- .add();
622
-
623
- //addEvent(button.element, 'click', revert);
624
-
625
- // add the click event
626
- if (menuItems) {
627
- onclick = function () {
628
- revert();
629
- var bBox = button.getBBox();
630
- chart.contextMenu('export-menu', menuItems, bBox.x, bBox.y, buttonWidth, buttonHeight);
631
- };
632
- }
633
- /*addEvent(button.element, 'click', function() {
634
- onclick.apply(chart, arguments);
635
- });*/
636
- button.on('click', function () {
637
- onclick.apply(chart, arguments);
638
- });
639
-
640
- // the icon
641
- symbol = renderer.symbol(
642
- btnOptions.symbol,
643
- btnOptions.symbolX,
644
- btnOptions.symbolY,
645
- (btnOptions.symbolSize || 12) / 2
646
- )
647
- .align(btnOptions, true)
648
- .attr(extend(symbolAttr, {
649
- 'stroke-width': btnOptions.symbolStrokeWidth || 1,
650
- zIndex: 20
651
- })).add();
652
-
653
- // Keep references to the renderer element so to be able to destroy them later.
654
- chart.exportSVGElements.push(box, button, symbol);
655
- },
656
-
657
- /**
658
- * Destroy the buttons.
659
- */
660
- destroyExport: function () {
661
- var i,
662
- chart = this,
663
- elem;
664
-
665
- // Destroy the extra buttons added
666
- for (i = 0; i < chart.exportSVGElements.length; i++) {
667
- elem = chart.exportSVGElements[i];
668
- // Destroy and null the svg/vml elements
669
- elem.onclick = elem.ontouchstart = null;
670
- chart.exportSVGElements[i] = elem.destroy();
671
- }
672
-
673
- // Destroy the divs for the menu
674
- for (i = 0; i < chart.exportDivElements.length; i++) {
675
- elem = chart.exportDivElements[i];
676
-
677
- // Remove the event handler
678
- removeEvent(elem, 'mouseleave');
679
-
680
- // Remove inline events
681
- chart.exportDivElements[i] = elem.onmouseout = elem.onmouseover = elem.ontouchstart = elem.onclick = null;
682
-
683
- // Destroy the div by moving to garbage bin
684
- discardElement(elem);
685
- }
686
- }
687
- });
688
-
689
- // Create the export icon
690
- HC.Renderer.prototype.symbols.exportIcon = function (x, y, radius) {
691
- return [
692
- M, // the disk
693
- x - radius, y + radius,
694
- L,
695
- x + radius, y + radius,
696
- x + radius, y + radius * 0.5,
697
- x - radius, y + radius * 0.5,
698
- 'Z',
699
- M, // the arrow
700
- x, y + radius * 0.5,
701
- L,
702
- x - radius * 0.5, y - radius / 3,
703
- x - radius / 6, y - radius / 3,
704
- x - radius / 6, y - radius,
705
- x + radius / 6, y - radius,
706
- x + radius / 6, y - radius / 3,
707
- x + radius * 0.5, y - radius / 3,
708
- 'Z'
709
- ];
710
- };
711
- // Create the print icon
712
- HC.Renderer.prototype.symbols.printIcon = function (x, y, radius) {
713
- return [
714
- M, // the printer
715
- x - radius, y + radius * 0.5,
716
- L,
717
- x + radius, y + radius * 0.5,
718
- x + radius, y - radius / 3,
719
- x - radius, y - radius / 3,
720
- 'Z',
721
- M, // the upper sheet
722
- x - radius * 0.5, y - radius / 3,
723
- L,
724
- x - radius * 0.5, y - radius,
725
- x + radius * 0.5, y - radius,
726
- x + radius * 0.5, y - radius / 3,
727
- 'Z',
728
- M, // the lower sheet
729
- x - radius * 0.5, y + radius * 0.5,
730
- L,
731
- x - radius * 0.75, y + radius,
732
- x + radius * 0.75, y + radius,
733
- x + radius * 0.5, y + radius * 0.5,
734
- 'Z'
735
- ];
736
- };
737
-
738
-
739
- // Add the buttons on chart load
740
- Chart.prototype.callbacks.push(function (chart) {
741
- var n,
742
- exportingOptions = chart.options.exporting,
743
- buttons = exportingOptions.buttons;
744
-
745
- if (exportingOptions.enabled !== false) {
746
-
747
- for (n in buttons) {
748
- chart.addButton(buttons[n]);
749
- }
750
-
751
- // Destroy the export elements at chart destroy
752
- addEvent(chart, 'destroy', chart.destroyExport);
753
- }
754
-
755
- });
756
-
757
-
758
- }());
1
+ /**
2
+ * @license Highcharts JS v2.3.3 (2012-10-04)
3
+ * Exporting module
4
+ *
5
+ * (c) 2010-2011 Torstein Hønsi
6
+ *
7
+ * License: www.highcharts.com/license
8
+ */
9
+
10
+ // JSLint options:
11
+ /*global Highcharts, document, window, Math, setTimeout */
12
+
13
+ (function () { // encapsulate
14
+
15
+ // create shortcuts
16
+ var HC = Highcharts,
17
+ Chart = HC.Chart,
18
+ addEvent = HC.addEvent,
19
+ removeEvent = HC.removeEvent,
20
+ createElement = HC.createElement,
21
+ discardElement = HC.discardElement,
22
+ css = HC.css,
23
+ merge = HC.merge,
24
+ each = HC.each,
25
+ extend = HC.extend,
26
+ math = Math,
27
+ mathMax = math.max,
28
+ doc = document,
29
+ win = window,
30
+ hasTouch = doc.documentElement.ontouchstart !== undefined,
31
+ M = 'M',
32
+ L = 'L',
33
+ DIV = 'div',
34
+ HIDDEN = 'hidden',
35
+ NONE = 'none',
36
+ PREFIX = 'highcharts-',
37
+ ABSOLUTE = 'absolute',
38
+ PX = 'px',
39
+ UNDEFINED,
40
+ defaultOptions = HC.getOptions();
41
+
42
+ // Add language
43
+ extend(defaultOptions.lang, {
44
+ downloadPNG: 'Download PNG image',
45
+ downloadJPEG: 'Download JPEG image',
46
+ downloadPDF: 'Download PDF document',
47
+ downloadSVG: 'Download SVG vector image',
48
+ exportButtonTitle: 'Export to raster or vector image',
49
+ printButtonTitle: 'Print the chart'
50
+ });
51
+
52
+ // Buttons and menus are collected in a separate config option set called 'navigation'.
53
+ // This can be extended later to add control buttons like zoom and pan right click menus.
54
+ defaultOptions.navigation = {
55
+ menuStyle: {
56
+ border: '1px solid #A0A0A0',
57
+ background: '#FFFFFF'
58
+ },
59
+ menuItemStyle: {
60
+ padding: '0 5px',
61
+ background: NONE,
62
+ color: '#303030',
63
+ fontSize: hasTouch ? '14px' : '11px'
64
+ },
65
+ menuItemHoverStyle: {
66
+ background: '#4572A5',
67
+ color: '#FFFFFF'
68
+ },
69
+
70
+ buttonOptions: {
71
+ align: 'right',
72
+ backgroundColor: {
73
+ linearGradient: [0, 0, 0, 20],
74
+ stops: [
75
+ [0.4, '#F7F7F7'],
76
+ [0.6, '#E3E3E3']
77
+ ]
78
+ },
79
+ borderColor: '#B0B0B0',
80
+ borderRadius: 3,
81
+ borderWidth: 1,
82
+ //enabled: true,
83
+ height: 20,
84
+ hoverBorderColor: '#909090',
85
+ hoverSymbolFill: '#81A7CF',
86
+ hoverSymbolStroke: '#4572A5',
87
+ symbolFill: '#E0E0E0',
88
+ //symbolSize: 12,
89
+ symbolStroke: '#A0A0A0',
90
+ //symbolStrokeWidth: 1,
91
+ symbolX: 11.5,
92
+ symbolY: 10.5,
93
+ verticalAlign: 'top',
94
+ width: 24,
95
+ y: 10
96
+ }
97
+ };
98
+
99
+
100
+
101
+ // Add the export related options
102
+ defaultOptions.exporting = {
103
+ //enabled: true,
104
+ //filename: 'chart',
105
+ type: 'image/png',
106
+ url: 'http://export.highcharts.com/',
107
+ width: 800,
108
+ buttons: {
109
+ exportButton: {
110
+ //enabled: true,
111
+ symbol: 'exportIcon',
112
+ x: -10,
113
+ symbolFill: '#A8BF77',
114
+ hoverSymbolFill: '#768F3E',
115
+ _id: 'exportButton',
116
+ _titleKey: 'exportButtonTitle',
117
+ menuItems: [{
118
+ textKey: 'downloadPNG',
119
+ onclick: function () {
120
+ this.exportChart();
121
+ }
122
+ }, {
123
+ textKey: 'downloadJPEG',
124
+ onclick: function () {
125
+ this.exportChart({
126
+ type: 'image/jpeg'
127
+ });
128
+ }
129
+ }, {
130
+ textKey: 'downloadPDF',
131
+ onclick: function () {
132
+ this.exportChart({
133
+ type: 'application/pdf'
134
+ });
135
+ }
136
+ }, {
137
+ textKey: 'downloadSVG',
138
+ onclick: function () {
139
+ this.exportChart({
140
+ type: 'image/svg+xml'
141
+ });
142
+ }
143
+ }
144
+ // Enable this block to add "View SVG" to the dropdown menu
145
+ /*
146
+ ,{
147
+
148
+ text: 'View SVG',
149
+ onclick: function () {
150
+ var svg = this.getSVG()
151
+ .replace(/</g, '\n&lt;')
152
+ .replace(/>/g, '&gt;');
153
+
154
+ doc.body.innerHTML = '<pre>' + svg + '</pre>';
155
+ }
156
+ } // */
157
+ ]
158
+
159
+ },
160
+ printButton: {
161
+ //enabled: true,
162
+ symbol: 'printIcon',
163
+ x: -36,
164
+ symbolFill: '#B5C9DF',
165
+ hoverSymbolFill: '#779ABF',
166
+ _id: 'printButton',
167
+ _titleKey: 'printButtonTitle',
168
+ onclick: function () {
169
+ this.print();
170
+ }
171
+ }
172
+ }
173
+ };
174
+
175
+
176
+
177
+ extend(Chart.prototype, {
178
+ /**
179
+ * Return an SVG representation of the chart
180
+ *
181
+ * @param additionalOptions {Object} Additional chart options for the generated SVG representation
182
+ */
183
+ getSVG: function (additionalOptions) {
184
+ var chart = this,
185
+ chartCopy,
186
+ sandbox,
187
+ svg,
188
+ seriesOptions,
189
+ options = merge(chart.options, additionalOptions); // copy the options and add extra options
190
+
191
+ // IE compatibility hack for generating SVG content that it doesn't really understand
192
+ if (!doc.createElementNS) {
193
+ /*jslint unparam: true*//* allow unused parameter ns in function below */
194
+ doc.createElementNS = function (ns, tagName) {
195
+ return doc.createElement(tagName);
196
+ };
197
+ /*jslint unparam: false*/
198
+ }
199
+
200
+ // create a sandbox where a new chart will be generated
201
+ sandbox = createElement(DIV, null, {
202
+ position: ABSOLUTE,
203
+ top: '-9999em',
204
+ width: chart.chartWidth + PX,
205
+ height: chart.chartHeight + PX
206
+ }, doc.body);
207
+
208
+ // override some options
209
+ extend(options.chart, {
210
+ renderTo: sandbox,
211
+ forExport: true
212
+ });
213
+ options.exporting.enabled = false; // hide buttons in print
214
+ options.chart.plotBackgroundImage = null; // the converter doesn't handle images
215
+
216
+ // prepare for replicating the chart
217
+ options.series = [];
218
+ each(chart.series, function (serie) {
219
+ seriesOptions = merge(serie.options, {
220
+ animation: false, // turn off animation
221
+ showCheckbox: false,
222
+ visible: serie.visible
223
+ });
224
+
225
+ if (!seriesOptions.isInternal) { // used for the navigator series that has its own option set
226
+
227
+ // remove image markers
228
+ if (seriesOptions && seriesOptions.marker && /^url\(/.test(seriesOptions.marker.symbol)) {
229
+ seriesOptions.marker.symbol = 'circle';
230
+ }
231
+
232
+ options.series.push(seriesOptions);
233
+ }
234
+ });
235
+
236
+ // generate the chart copy
237
+ chartCopy = new Highcharts.Chart(options);
238
+
239
+ // reflect axis extremes in the export
240
+ each(['xAxis', 'yAxis'], function (axisType) {
241
+ each(chart[axisType], function (axis, i) {
242
+ var axisCopy = chartCopy[axisType][i],
243
+ extremes = axis.getExtremes(),
244
+ userMin = extremes.userMin,
245
+ userMax = extremes.userMax;
246
+
247
+ if (userMin !== UNDEFINED || userMax !== UNDEFINED) {
248
+ axisCopy.setExtremes(userMin, userMax, true, false);
249
+ }
250
+ });
251
+ });
252
+
253
+ // get the SVG from the container's innerHTML
254
+ svg = chartCopy.container.innerHTML;
255
+
256
+ // free up memory
257
+ options = null;
258
+ chartCopy.destroy();
259
+ discardElement(sandbox);
260
+
261
+ // sanitize
262
+ svg = svg
263
+ .replace(/zIndex="[^"]+"/g, '')
264
+ .replace(/isShadow="[^"]+"/g, '')
265
+ .replace(/symbolName="[^"]+"/g, '')
266
+ .replace(/jQuery[0-9]+="[^"]+"/g, '')
267
+ .replace(/isTracker="[^"]+"/g, '')
268
+ .replace(/url\([^#]+#/g, 'url(#')
269
+ .replace(/<svg /, '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
270
+ .replace(/ href=/g, ' xlink:href=')
271
+ .replace(/\n/, ' ')
272
+ .replace(/<\/svg>.*?$/, '</svg>') // any HTML added to the container after the SVG (#894)
273
+ /* This fails in IE < 8
274
+ .replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weight
275
+ return s2 +'.'+ s3[0];
276
+ })*/
277
+
278
+ // Replace HTML entities, issue #347
279
+ .replace(/&nbsp;/g, '\u00A0') // no-break space
280
+ .replace(/&shy;/g, '\u00AD') // soft hyphen
281
+
282
+ // IE specific
283
+ .replace(/<IMG /g, '<image ')
284
+ .replace(/height=([^" ]+)/g, 'height="$1"')
285
+ .replace(/width=([^" ]+)/g, 'width="$1"')
286
+ .replace(/hc-svg-href="([^"]+)">/g, 'xlink:href="$1"/>')
287
+ .replace(/id=([^" >]+)/g, 'id="$1"')
288
+ .replace(/class=([^" ]+)/g, 'class="$1"')
289
+ .replace(/ transform /g, ' ')
290
+ .replace(/:(path|rect)/g, '$1')
291
+ .replace(/style="([^"]+)"/g, function (s) {
292
+ return s.toLowerCase();
293
+ });
294
+
295
+ // IE9 beta bugs with innerHTML. Test again with final IE9.
296
+ svg = svg.replace(/(url\(#highcharts-[0-9]+)&quot;/g, '$1')
297
+ .replace(/&quot;/g, "'");
298
+ if (svg.match(/ xmlns="/g).length === 2) {
299
+ svg = svg.replace(/xmlns="[^"]+"/, '');
300
+ }
301
+
302
+ return svg;
303
+ },
304
+
305
+ /**
306
+ * Submit the SVG representation of the chart to the server
307
+ * @param {Object} options Exporting options. Possible members are url, type and width.
308
+ * @param {Object} chartOptions Additional chart options for the SVG representation of the chart
309
+ */
310
+ exportChart: function (options, chartOptions) {
311
+ var form,
312
+ chart = this,
313
+ svg = chart.getSVG(merge(chart.options.exporting.chartOptions, chartOptions)); // docs
314
+
315
+ // merge the options
316
+ options = merge(chart.options.exporting, options);
317
+
318
+ // create the form
319
+ form = createElement('form', {
320
+ method: 'post',
321
+ action: options.url,
322
+ enctype: 'multipart/form-data'
323
+ }, {
324
+ display: NONE
325
+ }, doc.body);
326
+
327
+ // add the values
328
+ each(['filename', 'type', 'width', 'svg'], function (name) {
329
+ createElement('input', {
330
+ type: HIDDEN,
331
+ name: name,
332
+ value: {
333
+ filename: options.filename || 'chart',
334
+ type: options.type,
335
+ width: options.width,
336
+ svg: svg
337
+ }[name]
338
+ }, null, form);
339
+ });
340
+
341
+ // submit
342
+ form.submit();
343
+
344
+ // clean up
345
+ discardElement(form);
346
+ },
347
+
348
+ /**
349
+ * Print the chart
350
+ */
351
+ print: function () {
352
+
353
+ var chart = this,
354
+ container = chart.container,
355
+ origDisplay = [],
356
+ origParent = container.parentNode,
357
+ body = doc.body,
358
+ childNodes = body.childNodes;
359
+
360
+ if (chart.isPrinting) { // block the button while in printing mode
361
+ return;
362
+ }
363
+
364
+ chart.isPrinting = true;
365
+
366
+ // hide all body content
367
+ each(childNodes, function (node, i) {
368
+ if (node.nodeType === 1) {
369
+ origDisplay[i] = node.style.display;
370
+ node.style.display = NONE;
371
+ }
372
+ });
373
+
374
+ // pull out the chart
375
+ body.appendChild(container);
376
+
377
+ // print
378
+ win.print();
379
+
380
+ // allow the browser to prepare before reverting
381
+ setTimeout(function () {
382
+
383
+ // put the chart back in
384
+ origParent.appendChild(container);
385
+
386
+ // restore all body content
387
+ each(childNodes, function (node, i) {
388
+ if (node.nodeType === 1) {
389
+ node.style.display = origDisplay[i];
390
+ }
391
+ });
392
+
393
+ chart.isPrinting = false;
394
+
395
+ }, 1000);
396
+
397
+ },
398
+
399
+ /**
400
+ * Display a popup menu for choosing the export type
401
+ *
402
+ * @param {String} name An identifier for the menu
403
+ * @param {Array} items A collection with text and onclicks for the items
404
+ * @param {Number} x The x position of the opener button
405
+ * @param {Number} y The y position of the opener button
406
+ * @param {Number} width The width of the opener button
407
+ * @param {Number} height The height of the opener button
408
+ */
409
+ contextMenu: function (name, items, x, y, width, height) {
410
+ var chart = this,
411
+ navOptions = chart.options.navigation,
412
+ menuItemStyle = navOptions.menuItemStyle,
413
+ chartWidth = chart.chartWidth,
414
+ chartHeight = chart.chartHeight,
415
+ cacheName = 'cache-' + name,
416
+ menu = chart[cacheName],
417
+ menuPadding = mathMax(width, height), // for mouse leave detection
418
+ boxShadow = '3px 3px 10px #888',
419
+ innerMenu,
420
+ hide,
421
+ menuStyle;
422
+
423
+ // create the menu only the first time
424
+ if (!menu) {
425
+
426
+ // create a HTML element above the SVG
427
+ chart[cacheName] = menu = createElement(DIV, {
428
+ className: PREFIX + name
429
+ }, {
430
+ position: ABSOLUTE,
431
+ zIndex: 1000,
432
+ padding: menuPadding + PX
433
+ }, chart.container);
434
+
435
+ innerMenu = createElement(DIV, null,
436
+ extend({
437
+ MozBoxShadow: boxShadow,
438
+ WebkitBoxShadow: boxShadow,
439
+ boxShadow: boxShadow
440
+ }, navOptions.menuStyle), menu);
441
+
442
+ // hide on mouse out
443
+ hide = function () {
444
+ css(menu, { display: NONE });
445
+ };
446
+
447
+ addEvent(menu, 'mouseleave', hide);
448
+
449
+
450
+ // create the items
451
+ each(items, function (item) {
452
+ if (item) {
453
+ var div = createElement(DIV, {
454
+ onmouseover: function () {
455
+ css(this, navOptions.menuItemHoverStyle);
456
+ },
457
+ onmouseout: function () {
458
+ css(this, menuItemStyle);
459
+ },
460
+ innerHTML: item.text || chart.options.lang[item.textKey]
461
+ }, extend({
462
+ cursor: 'pointer'
463
+ }, menuItemStyle), innerMenu);
464
+
465
+ div[hasTouch ? 'ontouchstart' : 'onclick'] = function () {
466
+ hide();
467
+ item.onclick.apply(chart, arguments);
468
+ };
469
+
470
+ // Keep references to menu divs to be able to destroy them
471
+ chart.exportDivElements.push(div);
472
+ }
473
+ });
474
+
475
+ // Keep references to menu and innerMenu div to be able to destroy them
476
+ chart.exportDivElements.push(innerMenu, menu);
477
+
478
+ chart.exportMenuWidth = menu.offsetWidth;
479
+ chart.exportMenuHeight = menu.offsetHeight;
480
+ }
481
+
482
+ menuStyle = { display: 'block' };
483
+
484
+ // if outside right, right align it
485
+ if (x + chart.exportMenuWidth > chartWidth) {
486
+ menuStyle.right = (chartWidth - x - width - menuPadding) + PX;
487
+ } else {
488
+ menuStyle.left = (x - menuPadding) + PX;
489
+ }
490
+ // if outside bottom, bottom align it
491
+ if (y + height + chart.exportMenuHeight > chartHeight) {
492
+ menuStyle.bottom = (chartHeight - y - menuPadding) + PX;
493
+ } else {
494
+ menuStyle.top = (y + height - menuPadding) + PX;
495
+ }
496
+
497
+ css(menu, menuStyle);
498
+ },
499
+
500
+ /**
501
+ * Add the export button to the chart
502
+ */
503
+ addButton: function (options) {
504
+ var chart = this,
505
+ renderer = chart.renderer,
506
+ btnOptions = merge(chart.options.navigation.buttonOptions, options),
507
+ onclick = btnOptions.onclick,
508
+ menuItems = btnOptions.menuItems,
509
+ buttonWidth = btnOptions.width,
510
+ buttonHeight = btnOptions.height,
511
+ box,
512
+ symbol,
513
+ button,
514
+ borderWidth = btnOptions.borderWidth,
515
+ boxAttr = {
516
+ stroke: btnOptions.borderColor
517
+
518
+ },
519
+ symbolAttr = {
520
+ stroke: btnOptions.symbolStroke,
521
+ fill: btnOptions.symbolFill
522
+ },
523
+ symbolSize = btnOptions.symbolSize || 12;
524
+
525
+ // Keeps references to the button elements
526
+ if (!chart.exportDivElements) {
527
+ chart.exportDivElements = [];
528
+ chart.exportSVGElements = [];
529
+ }
530
+
531
+ if (btnOptions.enabled === false) {
532
+ return;
533
+ }
534
+
535
+ // element to capture the click
536
+ function revert() {
537
+ symbol.attr(symbolAttr);
538
+ box.attr(boxAttr);
539
+ }
540
+
541
+ // the box border
542
+ box = renderer.rect(
543
+ 0,
544
+ 0,
545
+ buttonWidth,
546
+ buttonHeight,
547
+ btnOptions.borderRadius,
548
+ borderWidth
549
+ )
550
+ //.translate(buttonLeft, buttonTop) // to allow gradients
551
+ .align(btnOptions, true)
552
+ .attr(extend({
553
+ fill: btnOptions.backgroundColor,
554
+ 'stroke-width': borderWidth,
555
+ zIndex: 19
556
+ }, boxAttr)).add();
557
+
558
+ // the invisible element to track the clicks
559
+ button = renderer.rect(
560
+ 0,
561
+ 0,
562
+ buttonWidth,
563
+ buttonHeight,
564
+ 0
565
+ )
566
+ .align(btnOptions)
567
+ .attr({
568
+ id: btnOptions._id,
569
+ fill: 'rgba(255, 255, 255, 0.001)',
570
+ title: chart.options.lang[btnOptions._titleKey],
571
+ zIndex: 21
572
+ }).css({
573
+ cursor: 'pointer'
574
+ })
575
+ .on('mouseover', function () {
576
+ symbol.attr({
577
+ stroke: btnOptions.hoverSymbolStroke,
578
+ fill: btnOptions.hoverSymbolFill
579
+ });
580
+ box.attr({
581
+ stroke: btnOptions.hoverBorderColor
582
+ });
583
+ })
584
+ .on('mouseout', revert)
585
+ .on('click', revert)
586
+ .add();
587
+
588
+ // add the click event
589
+ if (menuItems) {
590
+ onclick = function () {
591
+ revert();
592
+ var bBox = button.getBBox();
593
+ chart.contextMenu('export-menu', menuItems, bBox.x, bBox.y, buttonWidth, buttonHeight);
594
+ };
595
+ }
596
+ /*addEvent(button.element, 'click', function() {
597
+ onclick.apply(chart, arguments);
598
+ });*/
599
+ button.on('click', function () {
600
+ onclick.apply(chart, arguments);
601
+ });
602
+
603
+ // the icon
604
+ symbol = renderer.symbol(
605
+ btnOptions.symbol,
606
+ btnOptions.symbolX - (symbolSize / 2),
607
+ btnOptions.symbolY - (symbolSize / 2),
608
+ symbolSize,
609
+ symbolSize
610
+ )
611
+ .align(btnOptions, true)
612
+ .attr(extend(symbolAttr, {
613
+ 'stroke-width': btnOptions.symbolStrokeWidth || 1,
614
+ zIndex: 20
615
+ })).add();
616
+
617
+ // Keep references to the renderer element so to be able to destroy them later.
618
+ chart.exportSVGElements.push(box, button, symbol);
619
+ },
620
+
621
+ /**
622
+ * Destroy the buttons.
623
+ */
624
+ destroyExport: function () {
625
+ var i,
626
+ chart = this,
627
+ elem;
628
+
629
+ // Destroy the extra buttons added
630
+ for (i = 0; i < chart.exportSVGElements.length; i++) {
631
+ elem = chart.exportSVGElements[i];
632
+ // Destroy and null the svg/vml elements
633
+ elem.onclick = elem.ontouchstart = null;
634
+ chart.exportSVGElements[i] = elem.destroy();
635
+ }
636
+
637
+ // Destroy the divs for the menu
638
+ for (i = 0; i < chart.exportDivElements.length; i++) {
639
+ elem = chart.exportDivElements[i];
640
+
641
+ // Remove the event handler
642
+ removeEvent(elem, 'mouseleave');
643
+
644
+ // Remove inline events
645
+ chart.exportDivElements[i] = elem.onmouseout = elem.onmouseover = elem.ontouchstart = elem.onclick = null;
646
+
647
+ // Destroy the div by moving to garbage bin
648
+ discardElement(elem);
649
+ }
650
+ }
651
+ });
652
+
653
+ /**
654
+ * Crisp for 1px stroke width, which is default. In the future, consider a smarter,
655
+ * global function.
656
+ */
657
+ function crisp(arr) {
658
+ var i = arr.length;
659
+ while (i--) {
660
+ if (typeof arr[i] === 'number') {
661
+ arr[i] = Math.round(arr[i]) - 0.5;
662
+ }
663
+ }
664
+ return arr;
665
+ }
666
+
667
+ // Create the export icon
668
+ HC.Renderer.prototype.symbols.exportIcon = function (x, y, width, height) {
669
+ return crisp([
670
+ M, // the disk
671
+ x, y + width,
672
+ L,
673
+ x + width, y + height,
674
+ x + width, y + height * 0.8,
675
+ x, y + height * 0.8,
676
+ 'Z',
677
+ M, // the arrow
678
+ x + width * 0.5, y + height * 0.8,
679
+ L,
680
+ x + width * 0.8, y + height * 0.4,
681
+ x + width * 0.4, y + height * 0.4,
682
+ x + width * 0.4, y,
683
+ x + width * 0.6, y,
684
+ x + width * 0.6, y + height * 0.4,
685
+ x + width * 0.2, y + height * 0.4,
686
+ 'Z'
687
+ ]);
688
+ };
689
+ // Create the print icon
690
+ HC.Renderer.prototype.symbols.printIcon = function (x, y, width, height) {
691
+ return crisp([
692
+ M, // the printer
693
+ x, y + height * 0.7,
694
+ L,
695
+ x + width, y + height * 0.7,
696
+ x + width, y + height * 0.4,
697
+ x, y + height * 0.4,
698
+ 'Z',
699
+ M, // the upper sheet
700
+ x + width * 0.2, y + height * 0.4,
701
+ L,
702
+ x + width * 0.2, y,
703
+ x + width * 0.8, y,
704
+ x + width * 0.8, y + height * 0.4,
705
+ 'Z',
706
+ M, // the lower sheet
707
+ x + width * 0.2, y + height * 0.7,
708
+ L,
709
+ x, y + height,
710
+ x + width, y + height,
711
+ x + width * 0.8, y + height * 0.7,
712
+ 'Z'
713
+ ]);
714
+ };
715
+
716
+
717
+ // Add the buttons on chart load
718
+ Chart.prototype.callbacks.push(function (chart) {
719
+ var n,
720
+ exportingOptions = chart.options.exporting,
721
+ buttons = exportingOptions.buttons;
722
+
723
+ if (exportingOptions.enabled !== false) {
724
+
725
+ for (n in buttons) {
726
+ chart.addButton(buttons[n]);
727
+ }
728
+
729
+ // Destroy the export elements at chart destroy
730
+ addEvent(chart, 'destroy', chart.destroyExport);
731
+ }
732
+
733
+ });
734
+
735
+
736
+ }());