Merge pull request #16474 from sushantpaste/test-for-pr-13809
[civicrm-core.git] / templates / CRM / common / chart.tpl
1 {*
2 +--------------------------------------------------------------------+
3 | Copyright CiviCRM LLC. All rights reserved. |
4 | |
5 | This work is published under the GNU AGPLv3 license with some |
6 | permitted exceptions and without any warranty. For full license |
7 | and copyright information, see https://civicrm.org/licensing |
8 +--------------------------------------------------------------------+
9 *}
10 <script src="{$config->resourceBase}/bower_components/d3/d3.min.js"></script>
11 <script src="{$config->resourceBase}/bower_components/crossfilter2/crossfilter.min.js"></script>
12 <script src="{$config->resourceBase}/bower_components/dc-2.1.x/dc.min.js"></script>
13 <style src="{$config->resourceBase}/bower_components/dc-2.1.x/dc.min.css"></style>
14 {literal}
15 <style>
16 .dc-chart path.domain {
17 fill: none;
18 stroke: black;
19 }
20 </style>
21 <script type="text/javascript">
22 function createChart( chartID, divName, xSize, ySize, data ) {
23
24 var div = document.getElementById(divName);
25 if (!div) {
26 console.log("no element found for chart id ", divName);
27 return;
28 }
29
30 // Figure out suitable size based on container size.
31 // In some cases the containing element has no size. We should insist on a minimum size.
32 var w = Math.max(Math.min(div.clientWidth - 32, 800), 316);
33 var h = Math.min(400, parseInt(w / 2));
34
35 var chartNode = document.createElement('div');
36 var heading = document.createElement('h2');
37 heading.textContent = data.title;
38 heading.style.marginBottom = '1rem';
39 heading.style.textAlign = 'center';
40 div.style.width = w + 'px';
41 div.style.marginLeft = 'auto';
42 div.style.marginRight = 'auto';
43
44 var links = document.createElement('div');
45 links.style.textAlign = 'center';
46 links.style.marginBottom = '1rem';
47 var linkSVG = document.createElement('a');
48 linkSVG.href = '#';
49 linkSVG.textContent = 'Download chart (SVG)';
50 linkSVG.addEventListener('click', e => {
51 e.preventDefault();
52 e.stopPropagation();
53 // Create an image.
54 var svg = div.querySelector('svg');
55 var xml = new XMLSerializer().serializeToString(svg);
56 var image64 = 'data:image/svg+xml;base64,' + btoa(xml);
57
58 downloadImageUrl('image/svg+xml', image64, data.title.replace(/[^a-zA-Z0-9-]+/g, '') + '.svg');
59 });
60 function downloadImageUrl(mime, url, filename) {
61 var downloadLink = document.createElement('a');
62 downloadLink.download = filename;
63 downloadLink.href = url;
64 downloadLink.downloadurl = [mime, downloadLink.download, url].join(':');
65 document.body.append(downloadLink);
66 downloadLink.click();
67 document.body.removeChild(downloadLink);
68 }
69 var linkPNG = document.createElement('a');
70 linkPNG.href = '#';
71 linkPNG.textContent = 'Download chart (PNG)';
72 linkPNG.addEventListener('click', e => {
73 e.preventDefault();
74 e.stopPropagation();
75 // Create an image.
76
77 var canvas = document.createElement('canvas');
78 canvas.width = w;
79 canvas.height = h;
80 div.appendChild(canvas);
81
82 var svg = div.querySelector('svg');
83 var xml = new XMLSerializer().serializeToString(svg);
84 var svg64 = btoa(xml);
85 var b64Start = 'data:image/svg+xml;base64,';
86 var image64 = b64Start + svg64;
87
88 var img = document.createElement('img');
89 img.onload = function() {
90 canvas.getContext('2d').drawImage(img, 0, 0);
91 // canvas.style.display = 'block';
92 var imgURL = canvas.toDataURL('image/png');
93 downloadImageUrl('image/png', imgURL, data.title.replace(/[^a-zA-Z0-9-]+/g, '') + '.png');
94 div.removeChild(canvas);
95 };
96 img.src = image64;
97 });
98
99 links.appendChild(linkSVG);
100 links.appendChild(document.createTextNode(' | '));
101 links.appendChild(linkPNG);
102
103 var crossfilterData, ndx, dataDimension, dataGroup, chart;
104 ndx = crossfilter(data.values[0]);
105 dataDimension = ndx.dimension(d => d.label);
106 dataGroup = dataDimension.group().reduceSum(d => d.value);
107 var ordinals = data.values[0].map(d => d.label);
108
109 if (data.type === 'barchart') {
110 chart = dc.barChart(chartNode)
111 .width(w)
112 .height(h)
113 .dimension(dataDimension)
114 .group(dataGroup)
115 .gap(4) // px
116 .x(d3.scale.ordinal(ordinals).domain(ordinals))
117 .xUnits(dc.units.ordinal)
118 .margins({top: 10, right: 30, bottom: 30, left: 90})
119 .elasticY(true)
120 .renderLabel(false)
121 .renderHorizontalGridLines(true)
122 .title(item=> item.key + ': ' + item.value)
123 //.turnOnControls(true)
124 .renderTitle(true);
125 }
126 else if (data.type === 'piechart') {
127 chart = dc.pieChart(chartNode)
128 .width(w)
129 .height(h)
130 .radius(parseInt(h / 2) - 5) // define pie radius
131 .innerRadius(parseInt(h / 4) - 5) // optional
132 .externalRadiusPadding(5)
133 .legend(dc.legend().legendText(d => d.name).y(5))
134 .dimension(dataDimension)
135 .group(dataGroup)
136 .renderLabel(false)
137 .title(item=> item.key + ': ' + item.value)
138 .turnOnControls(true)
139 .renderTitle(true);
140 }
141 // Delay rendering so that animation looks good.
142 window.setTimeout(() => {
143 div.appendChild(heading);
144 div.appendChild(chartNode);
145 div.appendChild(links);
146
147 dc.renderAll();
148 }, 1500);
149 }
150 </script>
151 {/literal}