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