| @@ -1,140 +1,135 @@ | ||
| 1 | +// Format large numbers as abbreviated strings (e.g. 15437 → "15.4K"). | |
| 2 | +function tptnFormatNumber( value ) { | |
| 3 | + if ( value >= 1000000 ) { | |
| 4 | + return ( value / 1000000 ).toFixed( 1 ) + 'M'; | |
| 5 | + } | |
| 6 | + if ( value >= 1000 ) { | |
| 7 | + return ( value / 1000 ).toFixed( 1 ) + 'K'; | |
| 8 | + } | |
| 9 | + return value.toLocaleString(); | |
| 10 | +} | |
| 11 | + | |
| 12 | +// Resolve chart type and display options based on data length. | |
| 13 | +function tptnChartTypeConfig( length ) { | |
| 14 | + var config = { | |
| 15 | + chartType: 'bar', | |
| 16 | + chartFill: false, | |
| 17 | + backgroundColor: '#70c4e1', | |
| 18 | + pointBackgroundColor: '#70c4e1', | |
| 19 | + borderWidth: 0, | |
| 20 | + pointBorderColor: '#70c4e1', | |
| 21 | + pointRadius: 0, | |
| 22 | + showDataLabels: true, | |
| 23 | + }; | |
| 24 | + | |
| 25 | + if ( length > 50 ) { | |
| 26 | + config.chartType = 'line'; | |
| 27 | + config.chartFill = true; | |
| 28 | + config.backgroundColor = 'rgba(112, 196, 225, 0.2)'; | |
| 29 | + config.borderWidth = 2; | |
| 30 | + config.pointBorderColor = '#ffffff'; | |
| 31 | + config.pointRadius = 3; | |
| 32 | + config.showDataLabels = false; | |
| 33 | + } | |
| 34 | + | |
| 35 | + return config; | |
| 36 | +} | |
| 37 | + | |
| 1 | 38 | // Function to update the chart. |
| 2 | 39 | function updateChart() { |
| 3 | 40 | jQuery.post( |
| 4 | 41 | ajaxurl, |
| 5 | 42 | { |
| 6 | - action: "tptn_chart_data", | |
| 43 | + action: 'tptn_chart_data', | |
| 7 | 44 | security: tptn_chart_data.security, |
| 8 | - from_date: jQuery("#datepicker-from").val(), | |
| 9 | - to_date: jQuery("#datepicker-to").val(), | |
| 45 | + from_date: jQuery( '#datepicker-from' ).val(), | |
| 46 | + to_date: jQuery( '#datepicker-to' ).val(), | |
| 10 | 47 | network: tptn_chart_data.network, |
| 11 | 48 | }, |
| 12 | - function (data) { | |
| 13 | - var date = []; | |
| 49 | + function ( data ) { | |
| 50 | + var date = []; | |
| 14 | 51 | var visits = []; |
| 15 | 52 | |
| 16 | - for (var i in data) { | |
| 17 | - date.push(data[i].date); | |
| 18 | - visits.push(data[i].visits); | |
| 53 | + for ( var i in data ) { | |
| 54 | + date.push( data[ i ].date ); | |
| 55 | + visits.push( data[ i ].visits ); | |
| 19 | 56 | } |
| 20 | 57 | |
| 21 | - // Determine chart type based on number of datapoints | |
| 22 | - var chartType = "bar"; | |
| 23 | - var chartFill = false; | |
| 24 | - var backgroundColor = "#70c4e1"; | |
| 25 | - var pointBackgroundColor = "#70c4e1"; | |
| 26 | - var borderWidth = 0; | |
| 27 | - var pointBorderColor = "#70c4e1"; | |
| 28 | - var pointRadius = 0; | |
| 29 | - var showDataLabels = true; | |
| 58 | + var cfg = tptnChartTypeConfig( date.length ); | |
| 30 | 59 | |
| 31 | - // If we have more than 50 datapoints, switch to area chart for better visualization | |
| 32 | - if (date.length > 100) { | |
| 33 | - chartType = "line"; | |
| 34 | - chartFill = true; | |
| 35 | - backgroundColor = "rgba(112, 196, 225, 0.8)"; // Transparent blue | |
| 36 | - pointBackgroundColor = "#70c4e1"; // Solid blue dots | |
| 37 | - borderWidth = 2; | |
| 38 | - pointBorderColor = "#ffffff"; // White border around dots | |
| 39 | - pointRadius = 3; | |
| 40 | - showDataLabels = false; // Hide data labels for area chart to avoid clutter | |
| 41 | - } | |
| 60 | + if ( window.top10chart.config.type !== cfg.chartType ) { | |
| 61 | + window.top10chart.config.type = cfg.chartType; | |
| 62 | + window.top10chart.data.datasets.forEach( function ( dataset ) { | |
| 63 | + dataset.fill = cfg.chartFill; | |
| 64 | + dataset.backgroundColor = cfg.backgroundColor; | |
| 65 | + dataset.pointBackgroundColor = cfg.pointBackgroundColor; | |
| 66 | + dataset.borderWidth = cfg.borderWidth; | |
| 67 | + dataset.pointBorderColor = cfg.pointBorderColor; | |
| 68 | + dataset.pointRadius = cfg.pointRadius; | |
| 69 | + } ); | |
| 42 | 70 | |
| 43 | - // Update chart configuration if type needs to change | |
| 44 | - if (window.top10chart.config.type !== chartType) { | |
| 45 | - window.top10chart.config.type = chartType; | |
| 46 | - window.top10chart.data.datasets.forEach((dataset) => { | |
| 47 | - dataset.fill = chartFill; | |
| 48 | - dataset.backgroundColor = backgroundColor; | |
| 49 | - dataset.pointBackgroundColor = pointBackgroundColor; | |
| 50 | - dataset.borderWidth = borderWidth; | |
| 51 | - dataset.pointBorderColor = pointBorderColor; | |
| 52 | - dataset.pointRadius = pointRadius; | |
| 53 | - }); | |
| 54 | - | |
| 55 | - // Update data labels plugin display setting | |
| 56 | - if (window.top10chart.options && window.top10chart.options.plugins && window.top10chart.options.plugins.datalabels) { | |
| 57 | - window.top10chart.options.plugins.datalabels.display = showDataLabels; | |
| 71 | + if ( window.top10chart.options && window.top10chart.options.plugins && window.top10chart.options.plugins.datalabels ) { | |
| 72 | + window.top10chart.options.plugins.datalabels.display = cfg.showDataLabels ? 'auto' : false; | |
| 58 | 73 | } |
| 59 | 74 | } |
| 60 | 75 | |
| 61 | 76 | window.top10chart.data.labels = date; |
| 62 | - window.top10chart.data.datasets.forEach((dataset) => { | |
| 77 | + window.top10chart.data.datasets.forEach( function ( dataset ) { | |
| 63 | 78 | dataset.data = visits; |
| 64 | - }); | |
| 79 | + } ); | |
| 65 | 80 | window.top10chart.update(); |
| 66 | 81 | }, |
| 67 | - "json" | |
| 82 | + 'json' | |
| 68 | 83 | ); |
| 69 | 84 | } |
| 70 | 85 | |
| 71 | -jQuery(document).ready(function ($) { | |
| 72 | - $.ajax({ | |
| 73 | - type: "POST", | |
| 74 | - dataType: "json", | |
| 86 | +jQuery( document ).ready( function ( $ ) { | |
| 87 | + $.ajax( { | |
| 88 | + type: 'POST', | |
| 89 | + dataType: 'json', | |
| 75 | 90 | url: ajaxurl, |
| 76 | 91 | data: { |
| 77 | - action: "tptn_chart_data", | |
| 92 | + action: 'tptn_chart_data', | |
| 78 | 93 | security: tptn_chart_data.security, |
| 79 | - from_date: $("#datepicker-from").val(), | |
| 80 | - to_date: $("#datepicker-to").val(), | |
| 94 | + from_date: $( '#datepicker-from' ).val(), | |
| 95 | + to_date: $( '#datepicker-to' ).val(), | |
| 81 | 96 | network: tptn_chart_data.network, |
| 82 | 97 | }, |
| 83 | - success: function (data) { | |
| 84 | - var date = []; | |
| 98 | + success: function ( data ) { | |
| 99 | + var date = []; | |
| 85 | 100 | var visits = []; |
| 86 | 101 | |
| 87 | - for (var i in data) { | |
| 88 | - date.push(data[i].date); | |
| 89 | - visits.push(data[i].visits); | |
| 102 | + for ( var i in data ) { | |
| 103 | + date.push( data[ i ].date ); | |
| 104 | + visits.push( data[ i ].visits ); | |
| 90 | 105 | } |
| 91 | 106 | |
| 92 | - // Determine chart type based on number of datapoints | |
| 93 | - var chartType = "bar"; | |
| 94 | - var chartFill = false; | |
| 95 | - var backgroundColor = "#70c4e1"; | |
| 96 | - var pointBackgroundColor = "#70c4e1"; | |
| 97 | - var borderWidth = 0; | |
| 98 | - var pointBorderColor = "#70c4e1"; | |
| 99 | - var pointRadius = 0; | |
| 100 | - var showDataLabels = true; | |
| 107 | + var cfg = tptnChartTypeConfig( date.length ); | |
| 108 | + var ctx = $( '#visits' ); | |
| 109 | + var enableBarClick = !! ( tptn_chart_data && parseInt( tptn_chart_data.enableBarClick, 10 ) === 1 ); | |
| 101 | 110 | |
| 102 | - // If we have more than 50 datapoints, switch to area chart for better visualization | |
| 103 | - if (date.length > 50) { | |
| 104 | - chartType = "line"; | |
| 105 | - chartFill = true; | |
| 106 | - backgroundColor = "rgba(112, 196, 225, 0.2)"; // Transparent blue | |
| 107 | - pointBackgroundColor = "#70c4e1"; // Solid blue dots | |
| 108 | - borderWidth = 2; | |
| 109 | - pointBorderColor = "#ffffff"; // White border around dots | |
| 110 | - pointRadius = 3; | |
| 111 | - showDataLabels = false; // Hide data labels for area chart to avoid clutter | |
| 112 | - } | |
| 113 | - | |
| 114 | - var ctx = $("#visits"); | |
| 115 | - var enableBarClick = !!(tptn_chart_data && parseInt(tptn_chart_data.enableBarClick, 10) === 1); | |
| 116 | 111 | var config = { |
| 117 | - type: chartType, | |
| 112 | + type: cfg.chartType, | |
| 118 | 113 | data: { |
| 119 | 114 | labels: date, |
| 120 | 115 | datasets: [ |
| 121 | 116 | { |
| 122 | 117 | label: tptn_chart_data.datasetlabel, |
| 123 | - backgroundColor: backgroundColor, | |
| 124 | - borderColor: "#70c4e1", | |
| 125 | - hoverBackgroundColor: "#ffbf00", | |
| 126 | - hoverBorderColor: "#ffbf00", | |
| 118 | + backgroundColor: cfg.backgroundColor, | |
| 119 | + borderColor: '#70c4e1', | |
| 120 | + hoverBackgroundColor: '#ffbf00', | |
| 121 | + hoverBorderColor: '#ffbf00', | |
| 127 | 122 | data: visits, |
| 128 | - fill: chartFill, | |
| 129 | - pointBackgroundColor: pointBackgroundColor, | |
| 130 | - pointBorderColor: pointBorderColor, | |
| 131 | - pointRadius: pointRadius, | |
| 132 | - borderWidth: borderWidth, | |
| 123 | + fill: cfg.chartFill, | |
| 124 | + pointBackgroundColor: cfg.pointBackgroundColor, | |
| 125 | + pointBorderColor: cfg.pointBorderColor, | |
| 126 | + pointRadius: cfg.pointRadius, | |
| 127 | + borderWidth: cfg.borderWidth, | |
| 133 | 128 | }, |
| 134 | 129 | ], |
| 135 | 130 | }, |
| 136 | - plugins: [ChartDataLabels], | |
| 131 | + plugins: [ ChartDataLabels ], | |
| 137 | 132 | options: { |
| 138 | 133 | plugins: { |
| 139 | 134 | title: { |
| 140 | 135 | text: tptn_chart_data.charttitle, |
| @@ -141,40 +136,49 @@ | ||
| 141 | 136 | display: true, |
| 142 | 137 | }, |
| 143 | 138 | legend: { |
| 144 | 139 | display: false, |
| 145 | - position: "bottom", | |
| 140 | + position: 'bottom', | |
| 146 | 141 | }, |
| 147 | 142 | datalabels: { |
| 148 | - color: "#000000", | |
| 149 | - anchor: "end", | |
| 150 | - align: "top", | |
| 151 | - display: showDataLabels, | |
| 143 | + color: '#000000', | |
| 144 | + anchor: 'end', | |
| 145 | + align: 'top', | |
| 146 | + display: cfg.showDataLabels ? 'auto' : false, | |
| 147 | + font: { | |
| 148 | + size: 11, | |
| 149 | + }, | |
| 150 | + formatter: tptnFormatNumber, | |
| 152 | 151 | }, |
| 153 | 152 | }, |
| 154 | 153 | scales: { |
| 155 | 154 | x: { |
| 156 | - type: "time", | |
| 155 | + type: 'time', | |
| 157 | 156 | time: { |
| 158 | - tooltipFormat: "DD", | |
| 159 | - unit: "day", | |
| 157 | + tooltipFormat: 'DD', | |
| 158 | + unit: 'day', | |
| 160 | 159 | displayFormats: { |
| 161 | - day: "DD", | |
| 160 | + day: 'DD', | |
| 162 | 161 | }, |
| 163 | 162 | }, |
| 164 | 163 | title: { |
| 165 | 164 | display: false, |
| 166 | - labelString: "Date", | |
| 165 | + labelString: 'Date', | |
| 167 | 166 | }, |
| 168 | 167 | }, |
| 169 | 168 | y: { |
| 170 | - grace: "5%", | |
| 169 | + grace: '5%', | |
| 171 | 170 | suggestedMin: 0, |
| 172 | 171 | display: true, |
| 172 | + ticks: { | |
| 173 | + callback: function ( value ) { | |
| 174 | + return tptnFormatNumber( value ); | |
| 175 | + }, | |
| 176 | + }, | |
| 173 | 177 | title: { |
| 174 | 178 | display: false, |
| 175 | 179 | text: tptn_chart_data.datasetlabel, |
| 176 | - color: "#000", | |
| 180 | + color: '#000', | |
| 177 | 181 | padding: { top: 30, left: 0, right: 0, bottom: 0 }, |
| 178 | 182 | }, |
| 179 | 183 | }, |
| 180 | 184 | }, |
| @@ -180,43 +184,52 @@ | ||
| 180 | 184 | }, |
| 181 | 185 | }, |
| 182 | 186 | }; |
| 183 | 187 | |
| 184 | - if (enableBarClick) { | |
| 185 | - config.options.onClick = function (event, elements) { | |
| 186 | - if (elements.length > 0) { | |
| 187 | - var index = elements[0].index; | |
| 188 | - var clickedDate = date[index]; | |
| 189 | - // Format date for URL (d+M+Y format expected by Statistics page). | |
| 190 | - var dateObj = new Date(clickedDate); | |
| 191 | - var day = String(dateObj.getDate()).padStart(2, "0"); | |
| 192 | - var monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; | |
| 193 | - var month = monthNames[dateObj.getMonth()]; | |
| 194 | - var year = dateObj.getFullYear(); | |
| 195 | - var formattedDate = day + "+" + month + "+" + year; | |
| 188 | + if ( enableBarClick ) { | |
| 189 | + config.options.onClick = function ( event, elements ) { | |
| 190 | + if ( elements.length > 0 ) { | |
| 191 | + var index = elements[ 0 ].index; | |
| 192 | + var clickedDate = date[ index ]; | |
| 193 | + var dateObj = new Date( clickedDate ); | |
| 194 | + var day = String( dateObj.getDate() ).padStart( 2, '0' ); | |
| 195 | + var monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]; | |
| 196 | + var month = monthNames[ dateObj.getMonth() ]; | |
| 197 | + var year = dateObj.getFullYear(); | |
| 198 | + var formattedDate = day + '+' + month + '+' + year; | |
| 196 | 199 | |
| 197 | - // Build URL with date filters. | |
| 198 | - var url = tptn_chart_data.statsUrl + "&orderby=daily_count&order=desc&post-date-filter-from=" + formattedDate + "&post-date-filter-to=" + formattedDate; | |
| 199 | - window.open(url, "_blank"); | |
| 200 | + var url = tptn_chart_data.statsUrl + '&orderby=daily_count&order=desc&post-date-filter-from=' + formattedDate + '&post-date-filter-to=' + formattedDate; | |
| 201 | + window.open( url, '_blank' ); | |
| 200 | 202 | } |
| 201 | 203 | }; |
| 202 | 204 | |
| 203 | - config.options.onHover = function (event, elements) { | |
| 204 | - event.native.target.style.cursor = elements.length > 0 ? "pointer" : "default"; | |
| 205 | + config.options.onHover = function ( event, elements ) { | |
| 206 | + event.native.target.style.cursor = elements.length > 0 ? 'pointer' : 'default'; | |
| 205 | 207 | }; |
| 206 | 208 | |
| 207 | 209 | config.options.plugins.tooltip = { |
| 208 | 210 | callbacks: { |
| 211 | + label: function ( context ) { | |
| 212 | + return context.dataset.label + ': ' + context.parsed.y.toLocaleString(); | |
| 213 | + }, | |
| 209 | 214 | afterBody: function () { |
| 210 | 215 | return tptn_chart_data.clickBarHint; |
| 211 | 216 | }, |
| 212 | 217 | }, |
| 213 | 218 | }; |
| 219 | + } else { | |
| 220 | + config.options.plugins.tooltip = { | |
| 221 | + callbacks: { | |
| 222 | + label: function ( context ) { | |
| 223 | + return context.dataset.label + ': ' + context.parsed.y.toLocaleString(); | |
| 224 | + }, | |
| 225 | + }, | |
| 226 | + }; | |
| 214 | 227 | } |
| 215 | 228 | |
| 216 | - window.top10chart = new Chart(ctx, config); | |
| 229 | + window.top10chart = new Chart( ctx, config ); | |
| 217 | 230 | }, |
| 218 | - error: function (data) { | |
| 231 | + error: function ( data ) { | |
| 219 | 232 | // console.log(data); |
| 220 | 233 | }, |
| 221 | - }); | |
| 222 | -}); | |
| 234 | + } ); | |
| 235 | +} ); | |