contour 1.1.1 → 1.1.2.pre

Sign up to get free protection for your applications and to get access to all the features.
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
+ }());