NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name RingsDB Collection Statistics // @namespace http://tampermonkey.net/ // @version 8 // @description Generate information (table and graphs) about your collection informed at RingsDB.com. // @author Danilo // @copyright 2020, Danilo (https://github.com/danilopatro) // @license Apache-2.0 // @homepage https://github.com/danilopatro/RingsDB-Collection-Statistics // @supportURL https://github.com/danilopatro/RingsDB-Collection-Statistics/issues // @icon https://raw.githubusercontent.com/danilopatro/RingsDB-Collection-Statistics/master/icon-192.ico // @match *://www.ringsdb.com/collection/* // @match *://ringsdb.com/collection/* // @grant GM_getResourceText // @grant GM_addStyle // @require https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js // @require https://code.jquery.com/ui/1.12.1/jquery-ui.js // @require https://cdn.jsdelivr.net/npm/chart.js@3.0.0/dist/chart.min.js // @require https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.0.0 // @resource jqueryCSS https://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css // @run-at document-idle // ==/UserScript== /* var cards_api_url = window.location.href.includes('https') ? 'https://www.ringsdb.com/api/public/cards/' : 'http://www.ringsdb.com/api/public/cards/'; var packs_api_url = window.location.href.includes('https') ? 'https://www.ringsdb.com/api/public/packs/' : 'http://www.ringsdb.com/api/public/packs/'; var collection_url = window.location.href.includes('https') ? 'https://www.ringsdb.com/collection/packs' : 'http://www.ringsdb.com/collection/packs'; */ //var base_url = window.location.hostname //var base_url = window.location.hostname.includes('//www.') ? window.location.hostname : 'https://www.'.concat(window.location.hostname) var base_url = 'https://'.concat(window.location.hostname.replace('www.','')) //console.log('URL base: '+ base_url); var cards_api_url = base_url + '/api/public/cards/'; var packs_api_url = base_url + '/api/public/packs/'; var collection_url = base_url + '/collection/packs'; var Cards = new Array(); var Sets = new Array(); var Collection = new Array(); var Collection_codes = new Array(); var Cards_Collection = new Array(); var Cards_Quantity = 0; var Cards_Quantity_total = 0; var Cards_Quantity_unique = 0; var Cards_Quantity_unique_total = 0; var Packs_Quantity = new Array(); var Packs_Quantity_total = new Array(); var Packs_Quantity_unique = new Array(); var Packs_Quantity_unique_total = new Array(); var Sphere_Quantity = new Array(); var Sphere_Quantity_total = new Array(); var Sphere_Quantity_unique = new Array(); var Sphere_Quantity_unique_total = new Array(); var Type_Quantity = new Array(); var Type_Quantity_total = new Array(); var Type_Quantity_unique = new Array(); var Type_Quantity_unique_total = new Array(); var Sphere_colors = {Tactics: '#ED2E30', Spirit: '#00B1D4', Leadership: '#AD62A5', Lore: '#51B848', Neutral: '#616161', Baggins: '#B39E26', Fellowship: '#B56C0C'}; var Sphere_symbols = {Tactics: '<span class="icon icon-tactics fg-tactics"></span>', Spirit: '<span class="icon icon-spirit fg-spirit"></span>', Leadership: '<span class="icon icon-leadership fg-leadership"></span>', Lore: '<span class="icon icon-lore fg-lore"></span>', Neutral: '<span class="icon icon-neutral fg-neutral"></span>', Baggins: '<span class="icon icon-baggins fg-baggins"></span>', Fellowship: '<span class="icon icon-fellowship fg-fellowship"></span>'}; var Type_colors = {Hero: '#dc9336', Ally: '#b15553', Event: '#509aaf', Attachment: '#77ad52', 'Player Side Quest': '#878a75', Treasure: '#c4c23b', Campaign: '#a1e3ff', Contract: '#3f1e66'}; var newCSS = GM_getResourceText ("jqueryCSS"); GM_addStyle (newCSS); //GM_addStyle("#base { width: 100%; height: 100%; display: none; }"); GM_addStyle("#base { width: 100%; height: 100%; }"); GM_addStyle(".table_canvas { width: 100%; border-collapse:separate; border-spacing: 10px 15px; }"); GM_addStyle(".table_canvas td { width: 50%; }"); GM_addStyle(".table_canvas th { padding: 5px; text-align: center; font-size: 15px; background-color: #eee; width: 33%; ; border-collapse:separate; border: 1px solid #DDD; -webkit-box-shadow: 3px 3px 10px -5px rgba(0,0,0,0.75); -moz-box-shadow: 3px 3px 10px -5px rgba(0,0,0,0.75); box-shadow: 3px 3px 10px -5px rgba(0,0,0,0.75);}"); GM_addStyle(".table_cards { width: 100%; text-align: center; border-collapse:separate; border: 1px solid #DDD; -webkit-box-shadow: 3px 3px 10px -5px rgba(0,0,0,0.75); -moz-box-shadow: 3px 3px 10px -5px rgba(0,0,0,0.75); box-shadow: 3px 3px 10px -5px rgba(0,0,0,0.75); }"); GM_addStyle(".table_cards th { padding: 5px; text-align: center; background-color: #eee; width: 33%; }"); GM_addStyle(".table_cards td { padding: 5px; width: 33%; }"); GM_addStyle(".table_cards td:first-child { text-align: left; padding-left: 10%; }"); GM_addStyle(".table_cards tr:nth-child(odd) { background-color: #f5f5f5; }"); GM_addStyle(".table_cards tr:last-child { background-color: #eee; }"); GM_addStyle("canvas { width: 100%; height: 100%; }"); var graph_width = '100%'; var graph_height = graph_width; /** * Get HTML asynchronously * @param {String} url The URL to get HTML from * @param {Function} callback A callback funtion. Pass in "response" variable to use returned HTML. */ var getHTML = function ( url, callback ) { // Feature detection if ( !window.XMLHttpRequest ) return; // Create new request var xhr = new XMLHttpRequest(); // Setup callback xhr.onload = function() { if ( callback && typeof( callback ) === 'function' ) { callback( this.responseXML ); } } // Get the HTML //console.log(window.location); //console.log('Connection function getHTML:'); xhr.open( 'GET', url ); xhr.setRequestHeader('Access-Control-Allow-Credentials', 'true'); xhr.setRequestHeader('Access-Control-Allow-Origin', '*'); xhr.setRequestHeader('Access-Control-Allow-Methods', 'GET,OPTIONS,PATCH,DELETE,POST,PUT'); xhr.setRequestHeader('Access-Control-Allow-Headers', 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Authorization'); //xhr.setRequestHeader('X-PINGOTHER', 'pingpong'); //xhr.setRequestHeader('Access-Control-Request-Method', 'GET'); //xhr.setRequestHeader('Access-Control-Request-Headers', 'text/html'); //xhr.setRequestHeader("X-PINGOTHER", "pingpong"); //xhr.setRequestHeader("Content-Type", "text/xml"); //xhr.responseType = 'document'; xhr.send(); }; function criaDIV(stringCollection){ var html_corpo = " \ <TABLE class='table_cards'>"+generateTable(Sphere_Quantity_unique, Sphere_Quantity)+ "</TABLE> \ <br><button style='padding: 4px;' onclick=\"$(\'#base\').toggle()\">Show/Hide Charts</button><br><br> \ <div id='base' > \ <TABLE class='table_canvas'> \ <TR> \ <TH COLSPAN='2'>Graphs by Sphere</TH>\ </TR> <TR> \ <TD> <canvas width='"+graph_width+"' height='"+graph_height+"' id='sphere'> </canvas > </TD>\ <TD> <canvas width='"+graph_width+"' height='"+graph_height+"' id='spherePie'> </canvas > </TD>\ </TR> <TR> \ <TH COLSPAN='2'>Graphs by Type</TH>\ </TR> <TR> \ <TD> <canvas width='"+graph_width+"' height='"+graph_height+"' id='type'> </canvas > </TD>\ <TD> <canvas width='"+graph_width+"' height='"+graph_height+"' id='typePie'> </canvas > </TD>\ </TR> <TR> \ <TH COLSPAN='2'>Status of the Collection</TH>\ </TR> <TR> \ <TD> <canvas width='"+graph_width+"' height='"+graph_height+"' id='total'> </canvas > </TD>\ <TD> <canvas width='"+graph_width+"' height='"+graph_height+"' id='spherePolar'> </canvas > </TD>\ </TR> \ </TABLE> \ </div>"; return html_corpo; }; function carregaCollection (response) { var someElement = $( "label[class*='active']" , response).get(); if(someElement == null || someElement.length == 0) console.log("Not logged in RingsDb.com"); else { for(var i = 0; i < someElement.length; i++) { Collection.push(someElement[i].innerHTML); } filterCollection(); } } function filterCollection () { for(var i = 0; i < Sets.length; i++) { if(Collection.includes(Sets[i].name)) { Collection_codes.push(Sets[i].code); } } filterCards(); inputSearchString(); } function inputSearchString () { if(Collection_codes.length == 0) console.log("No code loaded."); else { $(criaDIV(" e:"+Collection_codes.join("|"))).insertBefore($("#owned_packs form")); geraChart(Sphere_Quantity, 'All cards', 'sphere', 'bar', Sphere_Quantity_unique, 'Distinct cards'); geraChart(Sphere_Quantity, 'All cards', 'spherePie', 'pie', Sphere_Quantity_unique, 'Distinct cards'); geraChart(Type_Quantity, 'All cards', 'type', 'bar', Type_Quantity_unique, 'Distinct cards'); geraChart(Type_Quantity, 'All cards', 'typePie', 'pie', Type_Quantity_unique, 'Distinct cards'); geraChart(Sphere_Quantity_unique, 'Distinct cards', 'spherePolar', 'polarArea', new Array(), '', Sphere_Quantity_unique_total); geraChart(Cards_Quantity_unique_total, 'Total', 'total', 'bar', Cards_Quantity_unique, '', new Array()); } } function loadCards (callback) { $.getJSON(cards_api_url, function(data) { for(var i = 0; i < data.length; i++) { Cards.push({ code: data[i].code, pack_name: data[i].pack_name, sphere_name: data[i].sphere_name, type_name: data[i].type_name, quantity: data[i].quantity }); } }); if ( callback && typeof( callback ) === 'function' ) { callback(); } } function loadSets (callback) { $.getJSON(packs_api_url, function(data) { for(var i = 0; i < data.length; i++) { Sets.push({ code: data[i].code, name: data[i].name }); } }); if ( callback && typeof( callback ) === 'function' ) { callback(); } getHTML(collection_url, carregaCollection); } function filterCards () { for(var i = 0; i < Cards.length; i++) { Cards_Quantity_total += Cards[i].quantity * Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1; Cards_Quantity_unique_total += 1; Packs_Quantity_total[Cards[i].pack_name] = isNaN(Packs_Quantity_total[Cards[i].pack_name]) ? Cards[i].quantity * Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1 : Packs_Quantity_total[Cards[i].pack_name] + Cards[i].quantity * Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1; Packs_Quantity_unique_total[Cards[i].pack_name] = isNaN(Packs_Quantity_unique_total[Cards[i].pack_name]) ? 1 : Packs_Quantity_unique_total[Cards[i].pack_name] + 1; Sphere_Quantity_total[Cards[i].sphere_name] = isNaN(Sphere_Quantity_total[Cards[i].sphere_name]) ? Cards[i].quantity * Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1 : Sphere_Quantity_total[Cards[i].sphere_name] + Cards[i].quantity * Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1; Sphere_Quantity_unique_total[Cards[i].sphere_name] = isNaN(Sphere_Quantity_unique_total[Cards[i].sphere_name]) ? 1 : Sphere_Quantity_unique_total[Cards[i].sphere_name] + 1; Type_Quantity_total[Cards[i].type_name] = isNaN(Type_Quantity_total[Cards[i].type_name]) ? Cards[i].quantity * Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1 : Type_Quantity_total[Cards[i].type_name] + Cards[i].quantity * Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1; Type_Quantity_unique_total[Cards[i].type_name] = isNaN(Type_Quantity_unique_total[Cards[i].type_name]) ? 1 : Type_Quantity_unique_total[Cards[i].type_name] + 1; if(Collection.includes(Cards[i].pack_name)) { Cards_Collection.push([Cards[i].pack_name, Cards[i].sphere_name, Cards[i].type_name, Cards[i].quantity]); Cards_Quantity += Cards[i].quantity * Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1; Cards_Quantity_unique += 1; Packs_Quantity[Cards[i].pack_name] = isNaN(Packs_Quantity[Cards[i].pack_name]) ? Cards[i].quantity * (Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1) : Packs_Quantity[Cards[i].pack_name] + Cards[i].quantity * (Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1); Packs_Quantity_unique[Cards[i].pack_name] = isNaN(Packs_Quantity_unique[Cards[i].pack_name]) ? 1 : Packs_Quantity_unique[Cards[i].pack_name] + 1; Sphere_Quantity[Cards[i].sphere_name] = isNaN(Sphere_Quantity[Cards[i].sphere_name]) ? Cards[i].quantity * (Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1) : Sphere_Quantity[Cards[i].sphere_name] + Cards[i].quantity * (Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1); Sphere_Quantity_unique[Cards[i].sphere_name] = isNaN(Sphere_Quantity_unique[Cards[i].sphere_name]) ? 1 : Sphere_Quantity_unique[Cards[i].sphere_name] + 1; Type_Quantity[Cards[i].type_name] = isNaN(Type_Quantity[Cards[i].type_name]) ? Cards[i].quantity * (Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1) : Type_Quantity[Cards[i].type_name] + Cards[i].quantity * (Cards[i].pack_name == 'Core Set' ? multipleCoreSets(Collection) : 1); Type_Quantity_unique[Cards[i].type_name] = isNaN(Type_Quantity_unique[Cards[i].type_name]) ? 1 : Type_Quantity_unique[Cards[i].type_name] + 1; } } } function multipleCoreSets(CollectionLoaded) { return CollectionLoaded.includes('3') ? 3 : CollectionLoaded.includes('2') ? 2 : 1; } // @source https://stackoverflow.com/questions/1058427/how-to-detect-if-a-variable-is-an-array function isArray(obj) { return Object.prototype.toString.call(obj) === '[object Array]'; } // @source https://stackoverflow.com/questions/6823286/create-unique-colors-using-javascript function randomColors(total, color = 240) { var i = 40 / (total - 1); // distribute the colors evenly on the hue range var r = []; // hold the generated colors for (var x=0; x<total; x++) { r.push(get_random_color(30+x*i, color)); // you can also alternate the saturation and value for even more contrast between the colors } return r; } function rand(min, max) { return min + Math.random() * (max - min); } function get_random_color(i, color) { var h = rand(color, color); var s = rand(100, 100); var l = rand(i, i); return 'hsl(' + h + ',' + s + '%,' + l + '%)'; } function numberWithPoints(x) { return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, "."); } function hideShow(element) { var x = document.getElementById(element); if (x.style.display === "none") { x.style.display = "block"; } else { x.style.display = "none"; } } function generateTable(data, data2, headers = ['Sphere','Number of distinct cards','Total number of cards' ]) { var html = '<tr>\r\n<th nowrap>' + headers[0] + '</th><th nowrap>' + headers[1] + '</th><th nowrap>'+ headers[2] + '</th></tr>\r\n'; var data_labels = Object.getOwnPropertyNames(data); var n_cards = 0; var q_cards = 0; data_labels.shift(); data = Object.values(data); data2 = Object.values(data2); if (typeof (data[0]) === 'undefined') { return null; } for (var row = 0; row < data.length; row++) { html += '<tr class="fg-'+data_labels[row].toLowerCase() +'">\r\n'; html += '<td>' + returnSymbol(data_labels[row]) + '</td><td>' + data[row] + '</td><td>' + data2[row] + '</td>\r\n'; html += '</tr>\r\n'; n_cards += data[row]; q_cards += data2[row]; } html += '<tr>\r\n'; html += '<td><b>TOTAL</b></td><td><b>' + n_cards + '</b></td><td><b>' + q_cards + '</b></td>\r\n'; html += '</tr>\r\n'; return html; } function returnSymbol(sphere) { var labels_info = Object.getOwnPropertyNames(Sphere_symbols); return Sphere_symbols[sphere] + " " + sphere; } function divideArrays(A1, A2) { var temp = new Array(); var kA1 = Object.getOwnPropertyNames(A1); kA1.shift(); for (var x = 0; x < kA1.length; x++) { temp[kA1[x]] = A1[kA1[x]]/A2[kA1[x]]; } return temp; } // @source https://stackoverflow.com/questions/5223/length-of-a-javascript-object Object.size = function(obj) { var size = 0, key; for (key in obj) { if (obj.hasOwnProperty(key)) size++; } return size; }; loadCards(loadSets); function geraChart(info, name, canvas, type = 'bar', info2 = info, name2 = name, info_tot = info, info2_tot = info2) { info = isArray(info) ? info : [info]; info2 = isArray(info2) ? info2 : [info2]; var labels_info = Object.getOwnPropertyNames(info); labels_info.shift(); var values_info = canvas == 'spherePolar' ? Object.values(divideArrays(info,info_tot)) : Object.values(info); var values_info2 = canvas == 'spherePolar' ? values_info2 = Object.values(divideArrays(info2,info2_tot)) : Object.values(info2); var data1 = { labels: name, data: values_info, backgroundColor: function(context) { var index = context.dataIndex; var value = context.dataset.data[index]; return Object.getOwnPropertyNames(Sphere_colors).includes(labels_info[index]) ? Sphere_colors[labels_info[index]] : // For Sphere graph Object.getOwnPropertyNames(Type_colors).includes(labels_info[index]) ? Type_colors[labels_info[index]] : // For Type graph labels_info[0] == 'Core Set' ? Object.values(randomColors(Object.size(labels_info), 0)) : // for Pack graph 'rgb(255,0,0,.1)'; }, borderWidth: ['pie', 'polarArea'].indexOf(type) > -1 ? 2 : canvas == 'total' ? 1 : 0, borderColor: canvas == 'total' ? "rgb(255,0,0,.5)" : "#fff", borderAlign: 'inner', order: 2, }; var data2 = { labels: name2, data: values_info2, backgroundColor: function(context) { var index = context.dataIndex; var value = context.dataset.data[index]; return Object.getOwnPropertyNames(Sphere_colors).includes(labels_info[index]) ? Sphere_colors[labels_info[index]] : // For Sphere graph Object.getOwnPropertyNames(Type_colors).includes(labels_info[index]) ? Type_colors[labels_info[index]] : // For Type graph labels_info[0] == 'Core Set' ? Object.values(randomColors(Object.size(labels_info), 0)) : // for Type graph 'rgb(0,0,255,.25)'; }, borderWidth: ['pie', 'polarArea'].indexOf(type) > -1 ? 2 : 0, borderColor: "#fff", borderAlign: 'inner', type: type == 'bar' ? 'line' : type, fill: type == 'bar' ? false : true, showLine: false, //canvas == 'total' lineTension: 0, pointStyle: 'dash', pointradius: 0, pointHoverRadius: 0, pointBorderWidth: 0, pointHoverBorderWidth: 0, pointBorderColor: "#fff", order: 1, }; var data3 = { labels: name2, data: values_info2, type: type, backgroundColor: function(context) { var index = context.dataIndex; var value = context.dataset.data[index]; return Object.getOwnPropertyNames(Sphere_colors).includes(labels_info[index]) ? Sphere_colors[labels_info[index]] : // For Sphere graph Object.getOwnPropertyNames(Type_colors).includes(labels_info[index]) ? Type_colors[labels_info[index]] : // For Type graph labels_info[0] == 'Core Set' ? Object.values(randomColors(Object.size(labels_info), 0)) : // for Type graph canvas == 'total' ? 'rgb(255,0,0,1)' : 'rgb(255,0,0,.25)'; }, borderWidth: ['pie', 'polarArea'].indexOf(type) > -1 ? 2 : 0, borderColor: "#fff", borderAlign: 'inner', fill: type == 'bar' ? true : true, showLine: false, order: 1, datalabels: { labels: { value: { color: 'white', font: { size: 18, }, } } } }; var data4 = { labels: name, data: values_info, backgroundColor: function(context) { var index = context.dataIndex; var value = context.dataset.data[index]; return Object.getOwnPropertyNames(Sphere_colors).includes(labels_info[index]) ? Sphere_colors[labels_info[index]] : // For Sphere graph Object.getOwnPropertyNames(Type_colors).includes(labels_info[index]) ? Type_colors[labels_info[index]] : // For Type graph labels_info[0] == 'Core Set' ? Object.values(randomColors(Object.size(labels_info), 0)) : // for Pack graph 'rgb(255,0,0,.1)'; }, borderWidth: ['pie', 'polarArea'].indexOf(type) > -1 ? 2 : canvas == 'total' ? 1 : 0, borderColor: canvas == 'total' ? "rgb(255,0,0,.5)" : "#fff", borderAlign: 'inner', order: 2, datalabels: { color: canvas == 'total' ? 'red' : null, font: { size: 18, }, } }; var barChartData = { labels: labels_info, datasets: isNaN(info2) ? [ data1 ] : [ canvas == 'total' ? data4 : data1, canvas == 'total' ? data3 : data2 ], }; var ctx = document.getElementById(canvas).getContext('2d'); var defaultOptions = { responsive: true, tooltips: { mode: type == 'pie' ? 'dataset' : 'index', intersect: true, position: type == 'pie' ? 'nearest' : 'average', callbacks: { title: function(tooltipItem, data) { console.log(data.labels[tooltipItem]); return type == 'pie' ? data.datasets[tooltipItem[0].datasetIndex].label+':' : tooltipItem[0].xLabel+':'; }, }, }, plugins: { title: { display: true, text: name +' Chart' }, legend: { display: false, position: 'bottom', labels: { usePointStyle: true, }, }, datalabels: { anchor: type == 'pie' ? 'center' : 'end', align: 'bottom', display: 'auto', formatter: (value, ctx) => { let sum = 0; let dataArr = ctx.chart.data.datasets[ctx.datasetIndex].data; dataArr.map(data => { sum += data; }); let percentage = type == 'pie' ? labels_info[ctx.dataIndex]+"\n"+(value*100 / sum).toFixed(1)+"%" : value; return percentage; }, color: '#fff', labels: { value: { font: { weight: 'bold' }, }, } } } }; var stackedOptions = { responsive: true, tooltips: { enabled: false, mode: type == 'pie' ? 'dataset' : 'index', intersect: true, position: type == 'pie' ? 'nearest' : 'average', }, scales: { x: { stacked: true, display: false, }, y: { stacked: false, ticks: { beginAtZero: true, stepSize: 100, }, }, }, plugins: { title: { display: true, text: 'Collection (distinct cards)' }, legend: { display: false, position: 'bottom', labels: { usePointStyle: true, }, }, datalabels: { anchor: type == 'pie' ? 'center' : 'end', align: 'bottom', display: 'auto', textAlign: 'center', formatter: (value, ctx) => { let sum = 0; let dataArr = ctx.chart.data.datasets[ctx.datasetIndex].data; dataArr.map(data => { sum += data; }); let percentage = type == 'pie' ? labels_info[ctx.dataIndex]+"\n"+(value*100 / sum).toFixed(1)+"%" : canvas == 'total' ? value+" cards\n"+(value*100 / Cards_Quantity_unique_total).toFixed(1)+"% of the total" : value; percentage = value == Cards_Quantity_unique_total ? value + ' cards published' : 'You own ' + value + " cards\n" + (value*100 / Cards_Quantity_unique_total).toFixed(1) + "% of the total"; return percentage; }, color: '#000', } }, }; var polarOptions = { responsive: true, tooltips: { mode: type == 'pie' ? 'dataset' : 'index', intersect: true, position: type == 'pie' ? 'nearest' : 'average', callbacks: { label: function(tooltipItem, data) { var label = data.labels[tooltipItem.index] || ''; label += ': ' + Sphere_Quantity_unique[data.labels[tooltipItem.index]] + ' of ' + Sphere_Quantity_unique_total[data.labels[tooltipItem.index]]; return label; }, } }, scale: { angleLines: { }, ticks: { min: 0, max: 1, stepSize: 0.1, callback: function(value, index, values) { return (value*100).toFixed(0)+"%"; }, }, }, plugins: { title: { display: true, text: 'Percent of '+name+' in the Collection in relation to those published by Sphere' }, legend: { display: true, position: 'right', labels: { usePointStyle: true, }, onClick: null, }, datalabels: { anchor: ['pie'].indexOf(type) > -1 ? 'center' : ['polarArea'].indexOf(type) > -1 ? 'end' : 'end', align: ['pie'].indexOf(type) > -1 ? 'bottom' : ['polarArea'].indexOf(type) > -1 ? 'start' : 'bottom', clamp: true, display: 'auto', formatter: (value, ctx) => { let sum = 0; let dataArr = ctx.chart.data.datasets[ctx.datasetIndex].data; dataArr.map(data => { sum += data; }); let percentage = ['pie'].indexOf(type) > -1 ? labels_info[ctx.dataIndex]+"\n"+(value*100 / sum).toFixed(1)+"%" : // For Pie graph ['polarArea'].indexOf(type) > -1 ? (value*100).toFixed(1)+"%" : // For Polar Area graph value; return percentage; }, color: '#fff', } }, }; var charBar = new Chart(ctx, { type: type, data: barChartData, plugins: [ChartDataLabels], options: type == 'polarArea' ? polarOptions : canvas == 'total' ? stackedOptions : defaultOptions, }); };