offline-exporting.src.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. /**
  2. * @license Highcharts JS v7.0.2 (2019-01-17)
  3. * Client side exporting module
  4. *
  5. * (c) 2015-2019 Torstein Honsi / Oystein Moseng
  6. *
  7. * License: www.highcharts.com/license
  8. */
  9. 'use strict';
  10. (function (factory) {
  11. if (typeof module === 'object' && module.exports) {
  12. factory['default'] = factory;
  13. module.exports = factory;
  14. } else if (typeof define === 'function' && define.amd) {
  15. define(function () {
  16. return factory;
  17. });
  18. } else {
  19. factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
  20. }
  21. }(function (Highcharts) {
  22. (function (Highcharts) {
  23. /* *
  24. * Mixin for downloading content in the browser
  25. *
  26. * (c) 2015-2019 Oystein Moseng
  27. *
  28. * License: www.highcharts.com/license
  29. */
  30. var win = Highcharts.win,
  31. nav = win.navigator,
  32. doc = win.document,
  33. domurl = win.URL || win.webkitURL || win,
  34. isEdgeBrowser = /Edge\/\d+/.test(nav.userAgent);
  35. // Convert base64 dataURL to Blob if supported, otherwise returns undefined
  36. Highcharts.dataURLtoBlob = function (dataURL) {
  37. var parts = dataURL.match(/data:([^;]*)(;base64)?,([0-9A-Za-z+/]+)/);
  38. if (
  39. parts &&
  40. parts.length > 3 &&
  41. win.atob &&
  42. win.ArrayBuffer &&
  43. win.Uint8Array &&
  44. win.Blob &&
  45. domurl.createObjectURL
  46. ) {
  47. // Try to convert data URL to Blob
  48. var binStr = win.atob(parts[3]),
  49. buf = new win.ArrayBuffer(binStr.length),
  50. binary = new win.Uint8Array(buf),
  51. blob;
  52. for (var i = 0; i < binary.length; ++i) {
  53. binary[i] = binStr.charCodeAt(i);
  54. }
  55. blob = new win.Blob([binary], { 'type': parts[1] });
  56. return domurl.createObjectURL(blob);
  57. }
  58. };
  59. /**
  60. * Download a data URL in the browser. Can also take a blob as first param.
  61. *
  62. * @private
  63. * @function Highcharts.downloadURL
  64. *
  65. * @param {string|object} dataURL
  66. * The dataURL/Blob to download
  67. *
  68. * @param {string} filename
  69. * The name of the resulting file (w/extension)
  70. */
  71. Highcharts.downloadURL = function (dataURL, filename) {
  72. var a = doc.createElement('a'),
  73. windowRef;
  74. // IE specific blob implementation
  75. // Don't use for normal dataURLs
  76. if (
  77. typeof dataURL !== 'string' &&
  78. !(dataURL instanceof String) &&
  79. nav.msSaveOrOpenBlob
  80. ) {
  81. nav.msSaveOrOpenBlob(dataURL, filename);
  82. return;
  83. }
  84. // Some browsers have limitations for data URL lengths. Try to convert to
  85. // Blob or fall back. Edge always needs that blob.
  86. if (isEdgeBrowser || dataURL.length > 2000000) {
  87. dataURL = Highcharts.dataURLtoBlob(dataURL);
  88. if (!dataURL) {
  89. throw new Error('Failed to convert to blob');
  90. }
  91. }
  92. // Try HTML5 download attr if supported
  93. if (a.download !== undefined) {
  94. a.href = dataURL;
  95. a.download = filename; // HTML5 download attribute
  96. doc.body.appendChild(a);
  97. a.click();
  98. doc.body.removeChild(a);
  99. } else {
  100. // No download attr, just opening data URI
  101. try {
  102. windowRef = win.open(dataURL, 'chart');
  103. if (windowRef === undefined || windowRef === null) {
  104. throw new Error('Failed to open window');
  105. }
  106. } catch (e) {
  107. // window.open failed, trying location.href
  108. win.location.href = dataURL;
  109. }
  110. }
  111. };
  112. }(Highcharts));
  113. (function (Highcharts) {
  114. /**
  115. * Client side exporting module
  116. *
  117. * (c) 2015 Torstein Honsi / Oystein Moseng
  118. *
  119. * License: www.highcharts.com/license
  120. */
  121. /* global MSBlobBuilder */
  122. var addEvent = Highcharts.addEvent,
  123. merge = Highcharts.merge,
  124. win = Highcharts.win,
  125. nav = win.navigator,
  126. doc = win.document,
  127. domurl = win.URL || win.webkitURL || win,
  128. isMSBrowser = /Edge\/|Trident\/|MSIE /.test(nav.userAgent),
  129. // Milliseconds to defer image load event handlers to offset IE bug
  130. loadEventDeferDelay = isMSBrowser ? 150 : 0;
  131. // Dummy object so we can reuse our canvas-tools.js without errors
  132. Highcharts.CanVGRenderer = {};
  133. /**
  134. * Downloads a script and executes a callback when done.
  135. *
  136. * @private
  137. * @function getScript
  138. *
  139. * @param {string} scriptLocation
  140. *
  141. * @param {Function} callback
  142. */
  143. function getScript(scriptLocation, callback) {
  144. var head = doc.getElementsByTagName('head')[0],
  145. script = doc.createElement('script');
  146. script.type = 'text/javascript';
  147. script.src = scriptLocation;
  148. script.onload = callback;
  149. script.onerror = function () {
  150. Highcharts.error('Error loading script ' + scriptLocation);
  151. };
  152. head.appendChild(script);
  153. }
  154. /**
  155. * Get blob URL from SVG code. Falls back to normal data URI.
  156. *
  157. * @private
  158. * @function Highcharts.svgToDataURL
  159. *
  160. * @param {string} svg
  161. *
  162. * @return {string}
  163. */
  164. Highcharts.svgToDataUrl = function (svg) {
  165. // Webkit and not chrome
  166. var webKit = (
  167. nav.userAgent.indexOf('WebKit') > -1 &&
  168. nav.userAgent.indexOf('Chrome') < 0
  169. );
  170. try {
  171. // Safari requires data URI since it doesn't allow navigation to blob
  172. // URLs. Firefox has an issue with Blobs and internal references,
  173. // leading to gradients not working using Blobs (#4550)
  174. if (!webKit && nav.userAgent.toLowerCase().indexOf('firefox') < 0) {
  175. return domurl.createObjectURL(new win.Blob([svg], {
  176. type: 'image/svg+xml;charset-utf-16'
  177. }));
  178. }
  179. } catch (e) {
  180. // Ignore
  181. }
  182. return 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg);
  183. };
  184. /**
  185. * Get data:URL from image URL. Pass in callbacks to handle results.
  186. *
  187. * @private
  188. * @function Highcharts.imageToDataUrl
  189. *
  190. * @param {string} imageURL
  191. *
  192. * @param {string} imageType
  193. *
  194. * @param {*} callbackArgs
  195. * callbackArgs is used only by callbacks.
  196. *
  197. * @param {number} scale
  198. *
  199. * @param {Function} successCallback
  200. * Receives four arguments: imageURL, imageType, callbackArgs, and scale.
  201. *
  202. * @param {Function} taintedCallback
  203. * Receives four arguments: imageURL, imageType, callbackArgs, and scale.
  204. *
  205. * @param {Function} noCanvasSupportCallback
  206. * Receives four arguments: imageURL, imageType, callbackArgs, and scale.
  207. *
  208. * @param {Function} failedLoadCallback
  209. * Receives four arguments: imageURL, imageType, callbackArgs, and scale.
  210. *
  211. * @param {Function} [finallyCallback]
  212. * finallyCallback is always called at the end of the process. All
  213. * callbacks receive four arguments: imageURL, imageType, callbackArgs,
  214. * and scale.
  215. */
  216. Highcharts.imageToDataUrl = function (
  217. imageURL,
  218. imageType,
  219. callbackArgs,
  220. scale,
  221. successCallback,
  222. taintedCallback,
  223. noCanvasSupportCallback,
  224. failedLoadCallback,
  225. finallyCallback
  226. ) {
  227. var img = new win.Image(),
  228. taintedHandler,
  229. loadHandler = function () {
  230. setTimeout(function () {
  231. var canvas = doc.createElement('canvas'),
  232. ctx = canvas.getContext && canvas.getContext('2d'),
  233. dataURL;
  234. try {
  235. if (!ctx) {
  236. noCanvasSupportCallback(
  237. imageURL,
  238. imageType,
  239. callbackArgs,
  240. scale
  241. );
  242. } else {
  243. canvas.height = img.height * scale;
  244. canvas.width = img.width * scale;
  245. ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
  246. // Now we try to get the contents of the canvas.
  247. try {
  248. dataURL = canvas.toDataURL(imageType);
  249. successCallback(
  250. dataURL,
  251. imageType,
  252. callbackArgs,
  253. scale
  254. );
  255. } catch (e) {
  256. taintedHandler(
  257. imageURL,
  258. imageType,
  259. callbackArgs,
  260. scale
  261. );
  262. }
  263. }
  264. } finally {
  265. if (finallyCallback) {
  266. finallyCallback(
  267. imageURL,
  268. imageType,
  269. callbackArgs,
  270. scale
  271. );
  272. }
  273. }
  274. // IE bug where image is not always ready despite calling load
  275. // event.
  276. }, loadEventDeferDelay);
  277. },
  278. // Image load failed (e.g. invalid URL)
  279. errorHandler = function () {
  280. failedLoadCallback(imageURL, imageType, callbackArgs, scale);
  281. if (finallyCallback) {
  282. finallyCallback(imageURL, imageType, callbackArgs, scale);
  283. }
  284. };
  285. // This is called on load if the image drawing to canvas failed with a
  286. // security error. We retry the drawing with crossOrigin set to Anonymous.
  287. taintedHandler = function () {
  288. img = new win.Image();
  289. taintedHandler = taintedCallback;
  290. // Must be set prior to loading image source
  291. img.crossOrigin = 'Anonymous';
  292. img.onload = loadHandler;
  293. img.onerror = errorHandler;
  294. img.src = imageURL;
  295. };
  296. img.onload = loadHandler;
  297. img.onerror = errorHandler;
  298. img.src = imageURL;
  299. };
  300. /**
  301. * Get data URL to an image of an SVG and call download on it options object:
  302. *
  303. * - **filename:** Name of resulting downloaded file without extension. Default
  304. * is `chart`.
  305. *
  306. * - **type:** File type of resulting download. Default is `image/png`.
  307. *
  308. * - **scale:** Scaling factor of downloaded image compared to source. Default
  309. * is `1`.
  310. *
  311. * - **libURL:** URL pointing to location of dependency scripts to download on
  312. * demand. Default is the exporting.libURL option of the global Highcharts
  313. * options pointing to our server.
  314. *
  315. * @function Highcharts.downloadSVGLocal
  316. *
  317. * @param {string} svg
  318. *
  319. * @param {Highcharts.ExportingOptions} options
  320. *
  321. * @param {Function} failCallback
  322. *
  323. * @param {Function} successCallback
  324. */
  325. Highcharts.downloadSVGLocal = function (
  326. svg,
  327. options,
  328. failCallback,
  329. successCallback
  330. ) {
  331. var svgurl,
  332. blob,
  333. objectURLRevoke = true,
  334. finallyHandler,
  335. libURL = options.libURL || Highcharts.getOptions().exporting.libURL,
  336. dummySVGContainer = doc.createElement('div'),
  337. imageType = options.type || 'image/png',
  338. filename = (
  339. (options.filename || 'chart') +
  340. '.' +
  341. (imageType === 'image/svg+xml' ? 'svg' : imageType.split('/')[1])
  342. ),
  343. scale = options.scale || 1;
  344. // Allow libURL to end with or without fordward slash
  345. libURL = libURL.slice(-1) !== '/' ? libURL + '/' : libURL;
  346. function svgToPdf(svgElement, margin) {
  347. var width = svgElement.width.baseVal.value + 2 * margin,
  348. height = svgElement.height.baseVal.value + 2 * margin,
  349. pdf = new win.jsPDF( // eslint-disable-line new-cap
  350. 'l',
  351. 'pt',
  352. [width, height]
  353. );
  354. // Workaround for #7090, hidden elements were drawn anyway. It comes
  355. // down to https://github.com/yWorks/svg2pdf.js/issues/28. Check this
  356. // later.
  357. [].forEach.call(
  358. svgElement.querySelectorAll('*[visibility="hidden"]'),
  359. function (node) {
  360. node.parentNode.removeChild(node);
  361. }
  362. );
  363. win.svg2pdf(svgElement, pdf, { removeInvalid: true });
  364. return pdf.output('datauristring');
  365. }
  366. function downloadPDF() {
  367. dummySVGContainer.innerHTML = svg;
  368. var textElements = dummySVGContainer.getElementsByTagName('text'),
  369. titleElements,
  370. svgData,
  371. // Copy style property to element from parents if it's not there.
  372. // Searches up hierarchy until it finds prop, or hits the chart
  373. // container.
  374. setStylePropertyFromParents = function (el, propName) {
  375. var curParent = el;
  376. while (curParent && curParent !== dummySVGContainer) {
  377. if (curParent.style[propName]) {
  378. el.style[propName] = curParent.style[propName];
  379. break;
  380. }
  381. curParent = curParent.parentNode;
  382. }
  383. };
  384. // Workaround for the text styling. Making sure it does pick up settings
  385. // for parent elements.
  386. [].forEach.call(textElements, function (el) {
  387. // Workaround for the text styling. making sure it does pick up the
  388. // root element
  389. ['font-family', 'font-size'].forEach(function (property) {
  390. setStylePropertyFromParents(el, property);
  391. });
  392. el.style['font-family'] = (
  393. el.style['font-family'] &&
  394. el.style['font-family'].split(' ').splice(-1)
  395. );
  396. // Workaround for plotband with width, removing title from text
  397. // nodes
  398. titleElements = el.getElementsByTagName('title');
  399. [].forEach.call(titleElements, function (titleElement) {
  400. el.removeChild(titleElement);
  401. });
  402. });
  403. svgData = svgToPdf(dummySVGContainer.firstChild, 0);
  404. try {
  405. Highcharts.downloadURL(svgData, filename);
  406. if (successCallback) {
  407. successCallback();
  408. }
  409. } catch (e) {
  410. failCallback(e);
  411. }
  412. }
  413. // Initiate download depending on file type
  414. if (imageType === 'image/svg+xml') {
  415. // SVG download. In this case, we want to use Microsoft specific Blob if
  416. // available
  417. try {
  418. if (nav.msSaveOrOpenBlob) {
  419. blob = new MSBlobBuilder();
  420. blob.append(svg);
  421. svgurl = blob.getBlob('image/svg+xml');
  422. } else {
  423. svgurl = Highcharts.svgToDataUrl(svg);
  424. }
  425. Highcharts.downloadURL(svgurl, filename);
  426. if (successCallback) {
  427. successCallback();
  428. }
  429. } catch (e) {
  430. failCallback(e);
  431. }
  432. } else if (imageType === 'application/pdf') {
  433. if (win.jsPDF && win.svg2pdf) {
  434. downloadPDF();
  435. } else {
  436. // Must load pdf libraries first. // Don't destroy the object URL
  437. // yet since we are doing things asynchronously. A cleaner solution
  438. // would be nice, but this will do for now.
  439. objectURLRevoke = true;
  440. getScript(libURL + 'jspdf.js', function () {
  441. getScript(libURL + 'svg2pdf.js', function () {
  442. downloadPDF();
  443. });
  444. });
  445. }
  446. } else {
  447. // PNG/JPEG download - create bitmap from SVG
  448. svgurl = Highcharts.svgToDataUrl(svg);
  449. finallyHandler = function () {
  450. try {
  451. domurl.revokeObjectURL(svgurl);
  452. } catch (e) {
  453. // Ignore
  454. }
  455. };
  456. // First, try to get PNG by rendering on canvas
  457. Highcharts.imageToDataUrl(
  458. svgurl,
  459. imageType,
  460. {},
  461. scale,
  462. function (imageURL) {
  463. // Success
  464. try {
  465. Highcharts.downloadURL(imageURL, filename);
  466. if (successCallback) {
  467. successCallback();
  468. }
  469. } catch (e) {
  470. failCallback(e);
  471. }
  472. }, function () {
  473. // Failed due to tainted canvas
  474. // Create new and untainted canvas
  475. var canvas = doc.createElement('canvas'),
  476. ctx = canvas.getContext('2d'),
  477. imageWidth = svg.match(
  478. /^<svg[^>]*width\s*=\s*\"?(\d+)\"?[^>]*>/
  479. )[1] * scale,
  480. imageHeight = svg.match(
  481. /^<svg[^>]*height\s*=\s*\"?(\d+)\"?[^>]*>/
  482. )[1] * scale,
  483. downloadWithCanVG = function () {
  484. ctx.drawSvg(svg, 0, 0, imageWidth, imageHeight);
  485. try {
  486. Highcharts.downloadURL(
  487. nav.msSaveOrOpenBlob ?
  488. canvas.msToBlob() :
  489. canvas.toDataURL(imageType),
  490. filename
  491. );
  492. if (successCallback) {
  493. successCallback();
  494. }
  495. } catch (e) {
  496. failCallback(e);
  497. } finally {
  498. finallyHandler();
  499. }
  500. };
  501. canvas.width = imageWidth;
  502. canvas.height = imageHeight;
  503. if (win.canvg) {
  504. // Use preloaded canvg
  505. downloadWithCanVG();
  506. } else {
  507. // Must load canVG first. // Don't destroy the object URL
  508. // yet since we are doing things asynchronously. A cleaner
  509. // solution would be nice, but this will do for now.
  510. objectURLRevoke = true;
  511. // Get RGBColor.js first, then canvg
  512. getScript(libURL + 'rgbcolor.js', function () {
  513. getScript(libURL + 'canvg.js', function () {
  514. downloadWithCanVG();
  515. });
  516. });
  517. }
  518. },
  519. // No canvas support
  520. failCallback,
  521. // Failed to load image
  522. failCallback,
  523. // Finally
  524. function () {
  525. if (objectURLRevoke) {
  526. finallyHandler();
  527. }
  528. }
  529. );
  530. }
  531. };
  532. /**
  533. * Get SVG of chart prepared for client side export. This converts embedded
  534. * images in the SVG to data URIs. It requires the regular exporting module. The
  535. * options and chartOptions arguments are passed to the getSVGForExport
  536. * function.
  537. *
  538. * @private
  539. * @function Highcharts.Chart#getSVGForLocalExport
  540. *
  541. * @param {Highcharts.ExportingOptions} options
  542. *
  543. * @param {Highcharts.Options} chartOptions
  544. *
  545. * @param {Function} failCallback
  546. *
  547. * @param {Function} successCallback
  548. */
  549. Highcharts.Chart.prototype.getSVGForLocalExport = function (
  550. options,
  551. chartOptions,
  552. failCallback,
  553. successCallback
  554. ) {
  555. var chart = this,
  556. images,
  557. imagesEmbedded = 0,
  558. chartCopyContainer,
  559. chartCopyOptions,
  560. el,
  561. i,
  562. l,
  563. // After grabbing the SVG of the chart's copy container we need to do
  564. // sanitation on the SVG
  565. sanitize = function (svg) {
  566. return chart.sanitizeSVG(svg, chartCopyOptions);
  567. },
  568. // Success handler, we converted image to base64!
  569. embeddedSuccess = function (imageURL, imageType, callbackArgs) {
  570. ++imagesEmbedded;
  571. // Change image href in chart copy
  572. callbackArgs.imageElement.setAttributeNS(
  573. 'http://www.w3.org/1999/xlink',
  574. 'href',
  575. imageURL
  576. );
  577. // When done with last image we have our SVG
  578. if (imagesEmbedded === images.length) {
  579. successCallback(sanitize(chartCopyContainer.innerHTML));
  580. }
  581. };
  582. // Hook into getSVG to get a copy of the chart copy's container (#8273)
  583. chart.unbindGetSVG = addEvent(chart, 'getSVG', function (e) {
  584. chartCopyOptions = e.chartCopy.options;
  585. chartCopyContainer = e.chartCopy.container.cloneNode(true);
  586. });
  587. // Trigger hook to get chart copy
  588. chart.getSVGForExport(options, chartOptions);
  589. images = chartCopyContainer.getElementsByTagName('image');
  590. try {
  591. // If there are no images to embed, the SVG is okay now.
  592. if (!images.length) {
  593. // Use SVG of chart copy
  594. successCallback(sanitize(chartCopyContainer.innerHTML));
  595. return;
  596. }
  597. // Go through the images we want to embed
  598. for (i = 0, l = images.length; i < l; ++i) {
  599. el = images[i];
  600. Highcharts.imageToDataUrl(
  601. el.getAttributeNS(
  602. 'http://www.w3.org/1999/xlink',
  603. 'href'
  604. ),
  605. 'image/png',
  606. { imageElement: el }, options.scale,
  607. embeddedSuccess,
  608. // Tainted canvas
  609. failCallback,
  610. // No canvas support
  611. failCallback,
  612. // Failed to load source
  613. failCallback
  614. );
  615. }
  616. } catch (e) {
  617. failCallback(e);
  618. }
  619. // Clean up
  620. chart.unbindGetSVG();
  621. };
  622. /**
  623. * Exporting and offline-exporting modules required. Export a chart to an image
  624. * locally in the user's browser. Requires the regular exporting module.
  625. *
  626. * @function Highcharts.Chart#exportChartLocal
  627. *
  628. * @param {Highcharts.ExportingOptions} exportingOptions
  629. * Exporting options, the same as in
  630. * {@link Highcharts.Chart#exportChart}.
  631. *
  632. * @param {Highcharts.Options} chartOptions
  633. * Additional chart options for the exported chart. For example a
  634. * different background color can be added here, or `dataLabels`
  635. * for export only.
  636. */
  637. Highcharts.Chart.prototype.exportChartLocal = function (
  638. exportingOptions,
  639. chartOptions
  640. ) {
  641. var chart = this,
  642. options = Highcharts.merge(chart.options.exporting, exportingOptions),
  643. fallbackToExportServer = function (err) {
  644. if (options.fallbackToExportServer === false) {
  645. if (options.error) {
  646. options.error(options, err);
  647. } else {
  648. Highcharts.error(28, true); // Fallback disabled
  649. }
  650. } else {
  651. chart.exportChart(options);
  652. }
  653. },
  654. svgSuccess = function (svg) {
  655. // If SVG contains foreignObjects all exports except SVG will fail,
  656. // as both CanVG and svg2pdf choke on this. Gracefully fall back.
  657. if (
  658. svg.indexOf('<foreignObject') > -1 &&
  659. options.type !== 'image/svg+xml'
  660. ) {
  661. fallbackToExportServer(
  662. 'Image type not supported for charts with embedded HTML'
  663. );
  664. } else {
  665. Highcharts.downloadSVGLocal(
  666. svg,
  667. Highcharts.extend(
  668. { filename: chart.getFilename() },
  669. options
  670. ),
  671. fallbackToExportServer
  672. );
  673. }
  674. };
  675. // If we are on IE and in styled mode, add a whitelist to the renderer for
  676. // inline styles that we want to pass through. There are so many styles by
  677. // default in IE that we don't want to blacklist them all.
  678. if (isMSBrowser && chart.styledMode) {
  679. Highcharts.SVGRenderer.prototype.inlineWhitelist = [
  680. /^blockSize/,
  681. /^border/,
  682. /^caretColor/,
  683. /^color/,
  684. /^columnRule/,
  685. /^columnRuleColor/,
  686. /^cssFloat/,
  687. /^cursor/,
  688. /^fill$/,
  689. /^fillOpacity/,
  690. /^font/,
  691. /^inlineSize/,
  692. /^length/,
  693. /^lineHeight/,
  694. /^opacity/,
  695. /^outline/,
  696. /^parentRule/,
  697. /^rx$/,
  698. /^ry$/,
  699. /^stroke/,
  700. /^textAlign/,
  701. /^textAnchor/,
  702. /^textDecoration/,
  703. /^transform/,
  704. /^vectorEffect/,
  705. /^visibility/,
  706. /^x$/,
  707. /^y$/
  708. ];
  709. }
  710. // Always fall back on:
  711. // - MS browsers: Embedded images JPEG/PNG, or any PDF
  712. // - Embedded images and PDF
  713. if (
  714. (
  715. isMSBrowser &&
  716. (
  717. options.type === 'application/pdf' ||
  718. chart.container.getElementsByTagName('image').length &&
  719. options.type !== 'image/svg+xml'
  720. )
  721. ) || (
  722. options.type === 'application/pdf' &&
  723. chart.container.getElementsByTagName('image').length
  724. )
  725. ) {
  726. fallbackToExportServer(
  727. 'Image type not supported for this chart/browser.'
  728. );
  729. return;
  730. }
  731. chart.getSVGForLocalExport(
  732. options,
  733. chartOptions,
  734. fallbackToExportServer,
  735. svgSuccess
  736. );
  737. };
  738. // Extend the default options to use the local exporter logic
  739. merge(true, Highcharts.getOptions().exporting, {
  740. libURL: 'https://code.highcharts.com/7.0.2/lib/',
  741. // When offline-exporting is loaded, redefine the menu item definitions
  742. // related to download.
  743. menuItemDefinitions: {
  744. downloadPNG: {
  745. textKey: 'downloadPNG',
  746. onclick: function () {
  747. this.exportChartLocal();
  748. }
  749. },
  750. downloadJPEG: {
  751. textKey: 'downloadJPEG',
  752. onclick: function () {
  753. this.exportChartLocal({
  754. type: 'image/jpeg'
  755. });
  756. }
  757. },
  758. downloadSVG: {
  759. textKey: 'downloadSVG',
  760. onclick: function () {
  761. this.exportChartLocal({
  762. type: 'image/svg+xml'
  763. });
  764. }
  765. },
  766. downloadPDF: {
  767. textKey: 'downloadPDF',
  768. onclick: function () {
  769. this.exportChartLocal({
  770. type: 'application/pdf'
  771. });
  772. }
  773. }
  774. }
  775. });
  776. }(Highcharts));
  777. return (function () {
  778. }());
  779. }));