6fb191e36c62163081c802c51304636219abdedc992c9b131ec61dd97b53854b9ad6021ad571be037e940db417966952d5626e8f96f6e25bb54135a6105eaf 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. <!-- Load c3.css -->
  2. <style>
  3. /*-- Chart --*/
  4. .c3 svg {
  5. font: 10px sans-serif;
  6. -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
  7. }
  8. .c3 path, .c3 line {
  9. fill: none;
  10. stroke: #000;
  11. }
  12. .c3 text {
  13. -webkit-user-select: none;
  14. -moz-user-select: none;
  15. user-select: none;
  16. }
  17. .c3-legend-item-tile,
  18. .c3-xgrid-focus,
  19. .c3-ygrid,
  20. .c3-event-rect,
  21. .c3-bars path {
  22. shape-rendering: crispEdges;
  23. }
  24. .c3-chart-arc path {
  25. stroke: #fff;
  26. }
  27. .c3-chart-arc rect {
  28. stroke: white;
  29. stroke-width: 1;
  30. }
  31. .c3-chart-arc text {
  32. fill: #fff;
  33. font-size: 13px;
  34. }
  35. /*-- Axis --*/
  36. /*-- Grid --*/
  37. .c3-grid line {
  38. stroke: #aaa;
  39. }
  40. .c3-grid text {
  41. fill: #aaa;
  42. }
  43. .c3-xgrid, .c3-ygrid {
  44. stroke-dasharray: 3 3;
  45. }
  46. /*-- Text on Chart --*/
  47. .c3-text.c3-empty {
  48. fill: #808080;
  49. font-size: 2em;
  50. }
  51. /*-- Line --*/
  52. .c3-line {
  53. stroke-width: 1px;
  54. }
  55. /*-- Point --*/
  56. .c3-circle._expanded_ {
  57. stroke-width: 1px;
  58. stroke: white;
  59. }
  60. .c3-selected-circle {
  61. fill: white;
  62. stroke-width: 2px;
  63. }
  64. /*-- Bar --*/
  65. .c3-bar {
  66. stroke-width: 0;
  67. }
  68. .c3-bar._expanded_ {
  69. fill-opacity: 1;
  70. fill-opacity: 0.75;
  71. }
  72. /*-- Focus --*/
  73. .c3-target.c3-focused {
  74. opacity: 1;
  75. }
  76. .c3-target.c3-focused path.c3-line, .c3-target.c3-focused path.c3-step {
  77. stroke-width: 2px;
  78. }
  79. .c3-target.c3-defocused {
  80. opacity: 0.3 !important;
  81. }
  82. /*-- Region --*/
  83. .c3-region {
  84. fill: steelblue;
  85. fill-opacity: 0.1;
  86. }
  87. /*-- Brush --*/
  88. .c3-brush .extent {
  89. fill-opacity: 0.1;
  90. }
  91. /*-- Select - Drag --*/
  92. /*-- Legend --*/
  93. .c3-legend-item {
  94. font-size: 12px;
  95. }
  96. .c3-legend-item-hidden {
  97. opacity: 0.15;
  98. }
  99. .c3-legend-background {
  100. opacity: 0.75;
  101. fill: white;
  102. stroke: lightgray;
  103. stroke-width: 1;
  104. }
  105. /*-- Title --*/
  106. .c3-title {
  107. font: 14px sans-serif;
  108. }
  109. /*-- Tooltip --*/
  110. .c3-tooltip-container {
  111. z-index: 10;
  112. }
  113. .c3-tooltip {
  114. border-collapse: collapse;
  115. border-spacing: 0;
  116. background-color: #fff;
  117. empty-cells: show;
  118. -webkit-box-shadow: 7px 7px 12px -9px #777777;
  119. -moz-box-shadow: 7px 7px 12px -9px #777777;
  120. box-shadow: 7px 7px 12px -9px #777777;
  121. opacity: 0.9;
  122. }
  123. .c3-tooltip tr {
  124. border: 1px solid #CCC;
  125. }
  126. .c3-tooltip th {
  127. background-color: #aaa;
  128. font-size: 14px;
  129. padding: 2px 5px;
  130. text-align: left;
  131. color: #FFF;
  132. }
  133. .c3-tooltip td {
  134. font-size: 13px;
  135. padding: 3px 6px;
  136. background-color: #fff;
  137. border-left: 1px dotted #999;
  138. }
  139. .c3-tooltip td > span {
  140. display: inline-block;
  141. width: 10px;
  142. height: 10px;
  143. margin-right: 6px;
  144. }
  145. .c3-tooltip td.value {
  146. text-align: right;
  147. }
  148. /*-- Area --*/
  149. .c3-area {
  150. stroke-width: 0;
  151. opacity: 0.2;
  152. }
  153. /*-- Arc --*/
  154. .c3-chart-arcs-title {
  155. dominant-baseline: middle;
  156. font-size: 1.3em;
  157. }
  158. .c3-chart-arcs .c3-chart-arcs-background {
  159. fill: #e0e0e0;
  160. stroke: #FFF;
  161. }
  162. .c3-chart-arcs .c3-chart-arcs-gauge-unit {
  163. fill: #000;
  164. font-size: 16px;
  165. }
  166. .c3-chart-arcs .c3-chart-arcs-gauge-max {
  167. fill: #777;
  168. }
  169. .c3-chart-arcs .c3-chart-arcs-gauge-min {
  170. fill: #777;
  171. }
  172. .c3-chart-arc .c3-gauge-value {
  173. fill: #000;
  174. /* font-size: 28px !important;*/
  175. }
  176. .c3-chart-arc.c3-target g path {
  177. opacity: 1;
  178. }
  179. .c3-chart-arc.c3-target.c3-focused g path {
  180. opacity: 1;
  181. }
  182. /*-- Zoom --*/
  183. .c3-drag-zoom.enabled {
  184. pointer-events: all !important;
  185. visibility: visible;
  186. }
  187. .c3-drag-zoom.disabled {
  188. pointer-events: none !important;
  189. visibility: hidden;
  190. }
  191. .c3-drag-zoom .extent {
  192. fill-opacity: 0.1;
  193. }
  194. </style>
  195. <!-- Load jQuery -->
  196. <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  197. <!-- Load d3.js and c3.js -->
  198. <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.js" charset="utf-8"></script>
  199. <script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.7/c3.js"></script>
  200. <!-- saveSVGtoPNG -->
  201. <script>
  202. (function() {
  203. const out$ = typeof exports != 'undefined' && exports || typeof define != 'undefined' && {} || this || window;
  204. if (typeof define !== 'undefined') define('save-svg-as-png', [], () => out$);
  205. const xmlns = 'http://www.w3.org/2000/xmlns/';
  206. const doctype = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [<!ENTITY nbsp "&#160;">]>';
  207. const urlRegex = /url\(["']?(.+?)["']?\)/;
  208. const fontFormats = {
  209. woff2: 'font/woff2',
  210. woff: 'font/woff',
  211. otf: 'application/x-font-opentype',
  212. ttf: 'application/x-font-ttf',
  213. eot: 'application/vnd.ms-fontobject',
  214. sfnt: 'application/font-sfnt',
  215. svg: 'image/svg+xml'
  216. };
  217. const isElement = obj => obj instanceof HTMLElement || obj instanceof SVGElement;
  218. const requireDomNode = el => {
  219. if (!isElement(el)) throw new Error(`an HTMLElement or SVGElement is required; got ${el}`);
  220. };
  221. const isExternal = url => url && url.lastIndexOf('http',0) === 0 && url.lastIndexOf(window.location.host) === -1;
  222. const getFontMimeTypeFromUrl = fontUrl => {
  223. const formats = Object.keys(fontFormats)
  224. .filter(extension => fontUrl.indexOf(`.${extension}`) > 0)
  225. .map(extension => fontFormats[extension]);
  226. if (formats) return formats[0];
  227. console.error(`Unknown font format for ${fontUrl}. Fonts may not be working correctly.`);
  228. return 'application/octet-stream';
  229. };
  230. const arrayBufferToBase64 = buffer => {
  231. let binary = '';
  232. const bytes = new Uint8Array(buffer);
  233. for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
  234. return window.btoa(binary);
  235. }
  236. const getDimension = (el, clone, dim) => {
  237. const v =
  238. (el.viewBox && el.viewBox.baseVal && el.viewBox.baseVal[dim]) ||
  239. (clone.getAttribute(dim) !== null && !clone.getAttribute(dim).match(/%$/) && parseInt(clone.getAttribute(dim))) ||
  240. el.getBoundingClientRect()[dim] ||
  241. parseInt(clone.style[dim]) ||
  242. parseInt(window.getComputedStyle(el).getPropertyValue(dim));
  243. return typeof v === 'undefined' || v === null || isNaN(parseFloat(v)) ? 0 : v;
  244. };
  245. const getDimensions = (el, clone, width, height) => {
  246. if (el.tagName === 'svg') return {
  247. width: width || getDimension(el, clone, 'width'),
  248. height: height || getDimension(el, clone, 'height')
  249. };
  250. else if (el.getBBox) {
  251. const {x, y, width, height} = el.getBBox();
  252. return {
  253. width: x + width,
  254. height: y + height
  255. };
  256. }
  257. };
  258. const reEncode = data =>
  259. decodeURIComponent(
  260. encodeURIComponent(data)
  261. .replace(/%([0-9A-F]{2})/g, (match, p1) => {
  262. const c = String.fromCharCode(`0x${p1}`);
  263. return c === '%' ? '%25' : c;
  264. })
  265. );
  266. const uriToBlob = uri => {
  267. const byteString = window.atob(uri.split(',')[1]);
  268. const mimeString = uri.split(',')[0].split(':')[1].split(';')[0]
  269. const buffer = new ArrayBuffer(byteString.length);
  270. const intArray = new Uint8Array(buffer);
  271. for (let i = 0; i < byteString.length; i++) {
  272. intArray[i] = byteString.charCodeAt(i);
  273. }
  274. return new Blob([buffer], {type: mimeString});
  275. };
  276. const query = (el, selector) => {
  277. if (!selector) return;
  278. try {
  279. return el.querySelector(selector) || el.parentNode && el.parentNode.querySelector(selector);
  280. } catch(err) {
  281. console.warn(`Invalid CSS selector "${selector}"`, err);
  282. }
  283. };
  284. const detectCssFont = (rule, href) => {
  285. // Match CSS font-face rules to external links.
  286. // @font-face {
  287. // src: local('Abel'), url(https://fonts.gstatic.com/s/abel/v6/UzN-iejR1VoXU2Oc-7LsbvesZW2xOQ-xsNqO47m55DA.woff2);
  288. // }
  289. const match = rule.cssText.match(urlRegex);
  290. const url = (match && match[1]) || '';
  291. if (!url || url.match(/^data:/) || url === 'about:blank') return;
  292. const fullUrl =
  293. url.startsWith('../') ? `${href}/../${url}`
  294. : url.startsWith('./') ? `${href}/.${url}`
  295. : url;
  296. return {
  297. text: rule.cssText,
  298. format: getFontMimeTypeFromUrl(fullUrl),
  299. url: fullUrl
  300. };
  301. };
  302. const inlineImages = el => Promise.all(
  303. Array.from(el.querySelectorAll('image')).map(image => {
  304. let href = image.getAttributeNS('http://www.w3.org/1999/xlink', 'href') || image.getAttribute('href');
  305. if (!href) return Promise.resolve(null);
  306. if (isExternal(href)) {
  307. href += (href.indexOf('?') === -1 ? '?' : '&') + 't=' + new Date().valueOf();
  308. }
  309. return new Promise((resolve, reject) => {
  310. const canvas = document.createElement('canvas');
  311. const img = new Image();
  312. img.crossOrigin = 'anonymous';
  313. img.src = href;
  314. img.onerror = () => reject(new Error(`Could not load ${href}`));
  315. img.onload = () => {
  316. canvas.width = img.width;
  317. canvas.height = img.height;
  318. canvas.getContext('2d').drawImage(img, 0, 0);
  319. image.setAttributeNS('http://www.w3.org/1999/xlink', 'href', canvas.toDataURL('image/png'));
  320. resolve(true);
  321. };
  322. });
  323. })
  324. );
  325. const cachedFonts = {};
  326. const inlineFonts = fonts => Promise.all(
  327. fonts.map(font =>
  328. new Promise((resolve, reject) => {
  329. if (cachedFonts[font.url]) return resolve(cachedFonts[font.url]);
  330. const req = new XMLHttpRequest();
  331. req.addEventListener('load', () => {
  332. // TODO: it may also be worth it to wait until fonts are fully loaded before
  333. // attempting to rasterize them. (e.g. use https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet)
  334. const fontInBase64 = arrayBufferToBase64(req.response);
  335. const fontUri = font.text.replace(urlRegex, `url("data:${font.format};base64,${fontInBase64}")`)+'\n';
  336. cachedFonts[font.url] = fontUri;
  337. resolve(fontUri);
  338. });
  339. req.addEventListener('error', e => {
  340. console.warn(`Failed to load font from: ${font.url}`, e);
  341. cachedFonts[font.url] = null;
  342. resolve(null);
  343. });
  344. req.addEventListener('abort', e => {
  345. console.warn(`Aborted loading font from: ${font.url}`, e);
  346. resolve(null);
  347. });
  348. req.open('GET', font.url);
  349. req.responseType = 'arraybuffer';
  350. req.send();
  351. })
  352. )
  353. ).then(fontCss => fontCss.filter(x => x).join(''));
  354. let cachedRules = null;
  355. const styleSheetRules = () => {
  356. if (cachedRules) return cachedRules;
  357. return cachedRules = Array.from(document.styleSheets).map(sheet => {
  358. try {
  359. return {rules: sheet.cssRules, href: sheet.href};
  360. } catch (e) {
  361. console.warn(`Stylesheet could not be loaded: ${sheet.href}`, e);
  362. return {};
  363. }
  364. });
  365. };
  366. const inlineCss = (el, options) => {
  367. const {
  368. selectorRemap,
  369. modifyStyle,
  370. modifyCss,
  371. fonts
  372. } = options || {};
  373. const generateCss = modifyCss || ((selector, properties) => {
  374. console.log(selectorRemap(selector));
  375. const sel = selectorRemap ? selectorRemap(selector) : selector;
  376. const props = modifyStyle ? modifyStyle(properties) : properties;
  377. return `${sel}{${props}}\n`;
  378. });
  379. const css = [];
  380. const detectFonts = typeof fonts === 'undefined';
  381. const fontList = fonts || [];
  382. styleSheetRules().forEach(({rules, href}) => {
  383. if (!rules) return;
  384. Array.from(rules).forEach(rule => {
  385. if (typeof rule.style != 'undefined') {
  386. if (query(el, rule.selectorText)) css.push(generateCss(rule.selectorText, rule.style.cssText));
  387. else if (detectFonts && rule.cssText.match(/^@font-face/)) {
  388. const font = detectCssFont(rule, href);
  389. if (font) fontList.push(font);
  390. } else css.push(rule.cssText);
  391. }
  392. });
  393. });
  394. return inlineFonts(fontList).then(fontCss => css.join('\n') + fontCss);
  395. };
  396. out$.prepareSvg = (el, options, done) => {
  397. requireDomNode(el);
  398. const {
  399. left = 0,
  400. top = 0,
  401. width: w,
  402. height: h,
  403. scale = 1,
  404. responsive = false,
  405. } = options || {};
  406. return inlineImages(el).then(() => {
  407. let clone = el.cloneNode(true);
  408. const {backgroundColor = 'transparent'} = options || {};
  409. clone.style.backgroundColor = backgroundColor;
  410. const {width, height} = getDimensions(el, clone, w, h);
  411. if (el.tagName !== 'svg') {
  412. if (el.getBBox) {
  413. clone.setAttribute('transform', clone.getAttribute('transform').replace(/translate\(.*?\)/, ''));
  414. const svg = document.createElementNS('http://www.w3.org/2000/svg','svg');
  415. svg.appendChild(clone);
  416. clone = svg;
  417. } else {
  418. console.error('Attempted to render non-SVG element', el);
  419. return;
  420. }
  421. }
  422. clone.setAttribute('version', '1.1');
  423. clone.setAttribute('viewBox', [left, top, width, height].join(' '));
  424. if (!clone.getAttribute('xmlns')) clone.setAttributeNS(xmlns, 'xmlns', 'http://www.w3.org/2000/svg');
  425. if (!clone.getAttribute('xmlns:xlink')) clone.setAttributeNS(xmlns, 'xmlns:xlink', 'http://www.w3.org/1999/xlink');
  426. if (responsive) {
  427. clone.removeAttribute('width');
  428. clone.removeAttribute('height');
  429. clone.setAttribute('preserveAspectRatio', 'xMinYMin meet');
  430. } else {
  431. clone.setAttribute('width', width * scale);
  432. clone.setAttribute('height', height * scale);
  433. }
  434. Array.from(clone.querySelectorAll('foreignObject > *')).forEach(foreignObject => {
  435. if (!foreignObject.getAttribute('xmlns'))
  436. foreignObject.setAttributeNS(xmlns, 'xmlns', 'http://www.w3.org/1999/xhtml');
  437. });
  438. return inlineCss(el, options).then(css => {
  439. const style = document.createElement('style');
  440. style.setAttribute('type', 'text/css');
  441. style.innerHTML = `<![CDATA[\n${css}\n]]>`;
  442. const defs = document.createElement('defs');
  443. defs.appendChild(style);
  444. clone.insertBefore(defs, clone.firstChild);
  445. const outer = document.createElement('div');
  446. outer.appendChild(clone);
  447. const src = outer.innerHTML.replace(/NS\d+:href/gi, 'xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href');
  448. if (typeof done === 'function') done(src, width, height);
  449. else return {src, width, height};
  450. });
  451. });
  452. };
  453. out$.svgAsDataUri = (el, options, done) => {
  454. requireDomNode(el);
  455. const result = out$.prepareSvg(el, options)
  456. .then(({src}) => `data:image/svg+xml;base64,${window.btoa(reEncode(doctype+src))}`);
  457. if (typeof done === 'function') return result.then(done);
  458. return result;
  459. };
  460. out$.svgAsPngUri = (el, options, done) => {
  461. requireDomNode(el);
  462. const {
  463. encoderType = 'image/png',
  464. encoderOptions = 0.8,
  465. canvg
  466. } = options || {};
  467. const convertToPng = ({src, width, height}) => {
  468. const canvas = document.createElement('canvas');
  469. const context = canvas.getContext('2d');
  470. const pixelRatio = window.devicePixelRatio || 1;
  471. canvas.width = width * pixelRatio;
  472. canvas.height = height * pixelRatio;
  473. canvas.style.width = `${canvas.width}px`;
  474. canvas.style.height = `${canvas.height}px`;
  475. context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
  476. if (canvg) canvg(canvas, src);
  477. else context.drawImage(src, 0, 0);
  478. let png;
  479. try {
  480. png = canvas.toDataURL(encoderType, encoderOptions);
  481. } catch (e) {
  482. if ((typeof SecurityError !== 'undefined' && e instanceof SecurityError) || e.name === 'SecurityError') {
  483. console.error('Rendered SVG images cannot be downloaded in this browser.');
  484. return;
  485. } else throw e;
  486. }
  487. if (typeof done === 'function') done(png);
  488. return Promise.resolve(png);
  489. }
  490. if (canvg) return out$.prepareSvg(el, options).then(convertToPng);
  491. else return out$.svgAsDataUri(el, options).then(uri => {
  492. return new Promise((resolve, reject) => {
  493. const image = new Image();
  494. image.onload = () => resolve(convertToPng({
  495. src: image,
  496. width: image.width,
  497. height: image.height
  498. }));
  499. image.onerror = () => {
  500. reject(`There was an error loading the data URI as an image on the following SVG\n${window.atob(uri.slice(26))}Open the following link to see browser's diagnosis\n${uri}`);
  501. }
  502. image.src = uri;
  503. })
  504. });
  505. };
  506. out$.download = (name, uri) => {
  507. if (navigator.msSaveOrOpenBlob) navigator.msSaveOrOpenBlob(uriToBlob(uri), name);
  508. else {
  509. const saveLink = document.createElement('a');
  510. if ('download' in saveLink) {
  511. saveLink.download = name;
  512. saveLink.style.display = 'none';
  513. document.body.appendChild(saveLink);
  514. try {
  515. const blob = uriToBlob(uri);
  516. const url = URL.createObjectURL(blob);
  517. saveLink.href = url;
  518. saveLink.onclick = () => requestAnimationFrame(() => URL.revokeObjectURL(url));
  519. } catch (e) {
  520. console.warn('This browser does not support object URLs. Falling back to string URL.');
  521. saveLink.href = uri;
  522. }
  523. saveLink.click();
  524. document.body.removeChild(saveLink);
  525. }
  526. else {
  527. window.open(uri, '_temp', 'menubar=no,toolbar=no,status=no');
  528. }
  529. }
  530. };
  531. out$.saveSvg = (el, name, options) => {
  532. requireDomNode(el);
  533. out$.svgAsDataUri(el, options || {}, uri => out$.download(name, uri));
  534. };
  535. out$.saveSvgAsPng = (el, name, options) => {
  536. requireDomNode(el);
  537. out$.svgAsPngUri(el, options || {}, uri => out$.download(name, uri));
  538. };
  539. })();
  540. </script>
  541. <!-- Generate cart -->
  542. <script>
  543. $(document).ready(function () {
  544. var chart = c3.generate({
  545. bindto: '#chart',
  546. data: {
  547. columns: [
  548. ['data1',
  549. 0.858926142,
  550. -3.111590247,
  551. -3.94420832,
  552. -4.175615293,
  553. -3.740784455,
  554. -3.416939753,
  555. -1.721508409,
  556. 0.187249078,
  557. -0.17687197,
  558. -3.234997643,
  559. -4.220987109,
  560. -0.956783273,
  561. -0.033680654,
  562. -0.140363168,
  563. 0.326102198,
  564. 0.639569773,
  565. 0.819556481,
  566. 0.351295891,
  567. 0.158211084
  568. ],
  569. ['data2',
  570. 4.013337337,
  571. -0.390845436,
  572. -0.84064409,
  573. -0.45909649,
  574. -0.223673085,
  575. 0.515092083,
  576. 1.441340134,
  577. 2.480247904,
  578. 2.052278238,
  579. 1.361221601,
  580. 0.722628463,
  581. 1.74097416,
  582. 2.109832697,
  583. 2.025055114,
  584. 2.192805826,
  585. 2.179848926,
  586. 1.976133973,
  587. 1.302580393,
  588. 0.883748718
  589. ],
  590. ['data3',
  591. 40.34831418,
  592. 38.37374131,
  593. 37.90326304,
  594. 38.22839717,
  595. 37.36657829,
  596. 37.31726398,
  597. 37.57459522,
  598. 37.63157371,
  599. 37.94299968,
  600. 38.33543337,
  601. 37.00018604,
  602. 37.46555832,
  603. 38.09271062,
  604. 38.45519135,
  605. 38.5445274,
  606. 38.77569391,
  607. 39.32543166,
  608. 39.36444162,
  609. 39.23532091
  610. ]
  611. ],
  612. names: {
  613. data1: 'Finanzierungssaldo',
  614. data2: 'Struktureller Primärsaldo',
  615. data3: 'Abgabenquote (rechte Skala)'
  616. },
  617. axes: {
  618. data3: 'y2' // ADD
  619. }
  620. },
  621. axis: {
  622. y: {
  623. label: { // ADD
  624. text: '%',
  625. position: 'inner-top',
  626. },
  627. max: 6,
  628. min: -6
  629. },
  630. y2: {
  631. show: true,
  632. label: { // ADD
  633. text: '%',
  634. position: 'inner-top'
  635. },
  636. max: 41,
  637. min: 35
  638. }
  639. }
  640. });
  641. d3.select(".c3-axis-y-label").attr("transform", "translate(20,0)");
  642. d3.select(".c3-axis-y2-label").attr("transform", "translate(0,17)");
  643. prepareSvg(document.querySelector('svg'), {selectorRemap: s => s.replace(/\.c3 /g, '')})
  644. .then(svg => document.getElementById('svg').innerHTML = svg.src);
  645. svgAsPngUri(document.querySelector('svg'), {selectorRemap: s => s.replace(/\.c3 /g, '')})
  646. .then(uri => document.getElementById('image').setAttribute('src', uri));
  647. });
  648. </script>
  649. <div id="chart" class="morechart"></div>
  650. <div id="svg"></div>
  651. <div><img id="image" /></div>